[cron:ac836bad-bf7b-40ae-8ac1-43d80be065c5 X Engagement - Helpful Replies (5/day)] SCHEDULED TASK: Post 1 helpful engagement reply on X/Twitter.

## CRITICAL: Use GHC profile ONLY
- SOCIAL_PROFILE=/home/crogers2287/.social-poster-profile-ghc
- NEVER use /home/crogers2287/.social-poster-profile/ (that's @cannadealsfl)
- NEVER use Maya VM twikit or cannadeals cookies

## CRITICAL: Only Recent Tweets (Last 2 Days)
When searching, ONLY consider tweets from the LAST 2 DAYS.
- Check the tweet timestamp before replying
- If the tweet is older than 48 hours, SKIP IT
- Look for "X hours ago" or "Yesterday" indicators
- NEVER reply to tweets from weeks/months/years ago

## Rules
- Search hashtags: #dealhunter #couponing #savemoney #amazondeal #frugalliving #budgettips #deals #bargain
- Find a REAL person's tweet (not a bot/spam account) that's RECENT (last 48 hours)
- Reply with something genuinely helpful
- NO self-promotion. No links to GottaHaveCoups. Just be helpful.
- NO hashtags on replies
- Log in memory/YYYY-MM-DD.md

## Method
cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster
SOCIAL_PROFILE=/home/crogers2287/.social-poster-profile-ghc xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" node post.mjs twitter-reply "<reply>" --url "<tweet_url>"
Current time: Sunday, February 15th, 2026 — 5:59 AM (UTC)

Return your summary as plain text; it will be delivered automatically. If the task explicitly calls for messaging a specific external recipient, note who/where it should go instead of sending it yourself.


The user wants me to post a helpful engagement reply on X/Twitter. Let me break down the requirements:

1. Use GHC profile ONLY: SOCIAL_PROFILE=/home/crogers2287/.social-poster-profile-ghc
2. Only reply to tweets from the LAST 2 DAYS
3. Search hashtags: #dealhunter #couponing #savemoney #amazondeal #frugalliving #budgettips #deals #bargain
4. Find a real person's tweet (not bot/spam)
5. Reply with something genuinely helpful
6. NO self-promotion, NO links to GottaHaveCoups
7. NO hashtags on replies
8. Log in memory/YYYY-MM-DD.md

The command structure is:
```
cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster
SOCIAL_PROFILE=/home/crogers2287/.social-poster-profile-ghc xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" node post.mjs twitter-reply "<reply>" --url "<tweet_url>"
```

First, I need to find a recent tweet to reply to. I should probably use the browser to search for these hashtags and find a recent tweet. Let me start by opening the browser and searching.

Actually, looking at the skills available, I should check if there's a social-poster skill that might help. Let me first navigate to the directory and understand what's available.

I'll help you post a helpful engagement reply on X/Twitter using the GHC profile. Let me start by navigating to the social-poster directory and finding a recent tweet to engage with.

exec

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && ls -la


total 188
drwxrwxr-x  3 crogers2287 crogers2287  4096 Feb 15 04:58 .
drwx---rwx  5 crogers2287 crogers2287  4096 Feb 12 13:41 ..
-rw-rw-r--  1 crogers2287 crogers2287  1406 Feb 12 02:30 _inject_ghc.mjs
-rw-rw-r--  1 crogers2287 crogers2287  1917 Feb 13 20:50 check_login.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3348 Feb 13 20:49 debug_search.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2808 Feb 12 13:06 delete_by_content.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2944 Feb 12 12:44 delete_tweet.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3396 Feb 15 04:13 find-tweets.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2093 Feb 13 20:51 find_tweets.mjs
-rwxrwxr-x  1 crogers2287 crogers2287  2153 Feb 14 00:01 find_tweets_fast.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2242 Feb 12 02:15 inject_ghc_cookies.mjs
-rw-rw-r--  1 crogers2287 crogers2287  1523 Feb 12 02:15 inject_ghc_pinterest.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2463 Feb 15 04:20 manual_login.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3095 Feb 14 01:16 maya_search.mjs
drwxrwxr-x 46 crogers2287 crogers2287  4096 Feb 12 01:19 node_modules
-rw-rw-r--  1 crogers2287 crogers2287 21575 Feb 12 01:19 package-lock.json
-rw-rw-r--  1 crogers2287 crogers2287   400 Feb 12 01:19 package.json
-rw-rw-r--  1 crogers2287 crogers2287  9826 Feb 14 23:43 post.mjs
-rwxrwxr-x  1 crogers2287 crogers2287  2653 Feb 14 00:02 post_fast.mjs
-rw-rw-r--  1 crogers2287 crogers2287  9825 Feb 14 03:28 post_fixed.mjs
-rw-rw-r--  1 crogers2287 crogers2287  9820 Feb 14 08:43 post_long_timeout.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2440 Feb 15 04:26 quick_login.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2935 Feb 12 01:33 reddit-login.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2899 Feb 14 03:26 search_authentic.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3381 Feb 15 04:58 search_authentic_personal.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2507 Feb 14 03:27 search_authentic_v2.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2506 Feb 14 09:43 search_authentic_v3.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3462 Feb 14 14:58 search_deals.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3463 Feb 14 23:41 search_deals_100.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3492 Feb 15 03:56 search_debug.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3353 Feb 15 00:44 search_grant.mjs
-rw-rw-r--  1 crogers2287 crogers2287  2577 Feb 14 12:53 search_grocery.mjs
-rw-rw-r--  1 crogers2287 crogers2287  1781 Feb 15 01:45 search_temp.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3420 Feb 13 20:49 search_tweets.mjs
-rw-rw-r--  1 crogers2287 crogers2287  1885 Feb 15 01:47 search_user.mjs
-rw-rw-r--  1 crogers2287 crogers2287  3206 Feb 15 04:40 simple_search.mjs


Good, I can see the social-poster directory. There's a find-tweets.mjs script that might be helpful. Let me search for tweets using the hashtags. I should use one of the search scripts to find recent tweets.

Let me try running the search_deals.mjs or find-tweets.mjs script to find recent tweets with those hashtags.

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && cat find-tweets.mjs


#!/usr/bin/env node
/**
 * Find tweets on X for engagement
 */

import { chromium } from 'playwright-extra';
import stealthPlugin from 'puppeteer-extra-plugin-stealth';
import { execSync } from 'child_process';
import path from 'path';
import fs from 'fs';

// Stealth
chromium.use(stealthPlugin());

// Config
const PROFILE_DIR = process.env.SOCIAL_PROFILE || '/home/crogers2287/.social-poster-profile-ghc';
const XVFB_DISPLAY = ':100';

// Ensure Xvfb is running
function ensureXvfb() {
  try {
    execSync(`pgrep -f "Xvfb ${XVFB_DISPLAY}"`, { stdio: 'ignore' });
  } catch {
    console.log('[*] Starting Xvfb...');
    execSync(`Xvfb ${XVFB_DISPLAY} -screen 0 1920x1080x24 &`, { stdio: 'ignore' });
    execSync('sleep 1');
  }
  process.env.DISPLAY = XVFB_DISPLAY;
}

async function launchBrowser(headless = false) {
  ensureXvfb();

  const browser = await chromium.launchPersistentContext(PROFILE_DIR, {
    headless: false,
    channel: undefined,
    viewport: { width: 1920, height: 1080 },
    args: [
      '--no-sandbox',
      '--disable-blink-features=AutomationControlled',
      '--disable-features=IsolateOrigins,site-per-process',
      `--display=${XVFB_DISPLAY}`,
    ],
    ignoreDefaultArgs: ['--enable-automation'],
  });

  return browser;
}

async function searchTweets() {
  const browser = await launchBrowser();
  const page = browser.pages()[0] || await browser.newPage();

  try {
    // Go to X search for recent #savemoney tweets
    await page.goto('https://x.com/search?q=%23savemoney%20OR%20%23couponing%20OR%20%23frugalliving%20OR%20%23deals&src=typed_query&f=live', {
      waitUntil: 'domcontentloaded',
      timeout: 60000
    });
    await page.waitForTimeout(3000);

    // Check if we're logged in
    const url = page.url();
    if (url.includes('/login') || url.includes('/i/flow/login')) {
      console.log('ERROR: Not logged in!');
      await browser.close();
      process.exit(1);
    }

    console.log('[+] Logged in, searching for tweets...');

    // Wait for tweets to load
    await page.waitForSelector('article[data-testid="tweet"]', { timeout: 30000 });

    // Extract tweet info
    const tweets = await page.evaluate(() => {
      const articles = document.querySelectorAll('article[data-testid="tweet"]');
      const results = [];

      articles.forEach((article, i) => {
        if (i >= 5) return; // Get first 5 tweets

        // Get tweet link
        const linkEl = article.querySelector('a[href*="/status/"]');
        const tweetUrl = linkEl ? `https://x.com${linkEl.getAttribute('href')}` : null;

        // Get tweet text
        const textEl = article.querySelector('[data-testid="tweetText"]');
        const text = textEl ? textEl.textContent : '';

        // Get username
        const userEl = article.querySelector('[data-testid="User-Name"] a');
        const username = userEl ? userEl.textContent : '';

        // Get time
        const timeEl = article.querySelector('time');
        const time = timeEl ? timeEl.getAttribute('datetime') : '';

        results.push({ tweetUrl, text, username, time });
      });

      return results;
    });

    console.log(JSON.stringify(tweets, null, 2));

  } catch (err) {
    console.error('Error:', err.message);
  } finally {
    await browser.close();
  }
}

searchTweets();


Perfect! I have a script to find tweets. Let me run this to find recent tweets with the relevant hashtags. I'll use the GHC profile.

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && SOCIAL_PROFILE=/home/crogers2287/.social-poster-profile-ghc node find-tweets.mjs


node:internal/process/promises:394
    triggerUncaughtException(err, true /* fromPromise */);
    ^

browserType.launchPersistentContext: Target page, context or browser has been closed
Browser logs:

╔════════════════════════════════════════════════════════════════════════════════════════════════╗
║ Looks like you launched a headed browser without having a XServer running.                     ║
║ Set either 'headless: true' or use 'xvfb-run <your-playwright-app>' before running Playwright. ║
║                                                                                ║
║ <3 Playwright Team                                                                             ║
╚════════════════════════════════════════════════════════════════════════════════════════════════╝
Call log:
  - <launching> /home/crogers2287/.cache/ms-playwright/chromium-1208/chrome-linux64/chrome --disable-field-trial-config --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-back-forward-cache --disable-breakpad --disable-client-side-phishing-detection --disable-component-update --no-default-browser-check --disable-dev-shm-usage --disable-features=AvoidUnnecessaryBeforeUnloadCheckSync,BoundaryEventDispatchTracksNodeRemoval,DestroyProfileOnBrowserClose,DialMediaRouteProvider,GlobalMediaControls,HttpsUpgrades,LensOverlay,MediaRouter,PaintHolding,ThirdPartyStoragePartitioning,Translate,AutoDeElevate,RenderDocument,OptimizationHints --enable-features=CDPScreenshotNewSurface --allow-pre-commit-input --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --force-color-profile=srgb --metrics-recording-only --no-first-run --password-store=basic --use-mock-keychain --no-service-autorun --export-tagged-pdf --disable-search-engine-choice-screen --unsafely-disable-devtools-self-xss-warnings --edge-skip-compat-layer-relaunch --disable-infobars --disable-search-engine-choice-screen --disable-sync --enable-unsafe-swiftshader --no-sandbox --no-sandbox --disable-blink-features=AutomationControlled,AutomationControlled --disable-features=IsolateOrigins,site-per-process --display=:100 --user-data-dir=/home/crogers2287/.social-poster-profile-ghc --remote-debugging-pipe about:blank
  - <launched> pid=2950699
  - [pid=2950699][err] [2950699:2950699:0215/055914.940293:ERROR:ui/ozone/platform/x11/ozone_platform_x11.cc:256] Missing X server or $DISPLAY
  - [pid=2950699][err] [2950699:2950699:0215/055914.940369:ERROR:ui/aura/env.cc:246] The platform failed to initialize.  Exiting.
  - [pid=2950699] <gracefully close start>
  - [pid=2950699] <kill>
  - [pid=2950699] <will force kill>
  - [pid=2950699] <process did exit: exitCode=1, signal=null>
  - [pid=2950699] starting temporary directories cleanup
  - [pid=2950699] finished temporary directories cleanup
  - [pid=2950699] <gracefully close end>

    at async Proxy.launchPersistentContext (/home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster/node_modules/playwright-extra/dist/index.cjs.js:703:25)
    at async launchBrowser (/home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster/find-tweets.mjs:34:19)
    at async searchTweets (/home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster/find-tweets.mjs:51:19)

Node.js v22.20.0

Command exited with code 1


The Xvfb display isn't working correctly. Let me try running it with xvfb-run instead.

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && SOCIAL_PROFILE=/home/crogers2287/.social-poster-profile-ghc xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" node find-tweets.mjs


[+] Logged in, searching for tweets...
[
  {
    "tweetUrl": "https://x.com/Austin894742999/status/2022913075842551832",
    "text": "J-B Weld PlasticWeld Quick-Setting Epoxy Syringe 25-ml (Translucent Yellow) $4.95  *ad\nhttps://slickdeals.net/f/19210321-4-97-25-ml-j-b-weld-plasticweld-quick-setting-epoxy-syringe-translucent-yellow-at-amazon?utm_source=rss&utm_content=fp&utm_medium=RSS2&utm_source=twitter… #deals",
    "username": "Austin",
    "time": "2026-02-15T05:57:15.000Z"
  },
  {
    "tweetUrl": "https://x.com/CentralMarkdown/status/2022911909297881515",
    "text": "60% off - Stanley IceFlow Fast Flow Water Bottle 24 oz | Angled Spout Lid |\n\nNow $14.00 - https://amazon.com/dp/B0CWLQPL7J?tag=centralmarkdo-20… #ad #deals\n\nNot bad for a Stanley! ",
    "username": "Central Markdown",
    "time": "2026-02-15T05:52:37.000Z"
  },
  {
    "tweetUrl": "https://x.com/wasim_asad/status/2022911806751281629",
    "text": "Download from the app store today. https://apps.apple.com/in/app/smart-finance-expense-tracker/id6758128481….  \n\n#PersonalGrowth #savemoney #budget #managesubscriptions #monthlybudget",
    "username": "Smart Finance App",
    "time": "2026-02-15T05:52:13.000Z"
  },
  {
    "tweetUrl": "https://x.com/Austin894742999/status/2022911796038742423",
    "text": "VEVOR 500-Lbs Heavy Duty Steel Wagon Cart $61.90  *ad\nhttps://slickdeals.net/f/19206262-61-9-vevor-500-lbs-steel-garden-cart-heavy-duty-wagon-with-10-all-terrain-tires-removable-mesh-sides-180-rotating-handle-pullable-on-wheels-at-amazon-com?utm_source=rss&utm_content=fp&utm_medium=RSS2&utm_source=twitter… #deals",
    "username": "Austin",
    "time": "2026-02-15T05:52:10.000Z"
  },
  {
    "tweetUrl": "https://x.com/Austin894742999/status/2022911794130415800",
    "text": "6-Pairs adidas Men's Athletic Cushioned Pack No Show Socks (Medium) $9.20  *ad\nhttps://slickdeals.net/f/19202290-9-17-6-pack-adidas-men-s-athletic-cushioned-no-show-socks-medium-at-amazon?utm_source=rss&utm_content=fp&utm_medium=RSS2&utm_source=twitter… #deals",
    "username": "Austin",
    "time": "2026-02-15T05:52:10.000Z"
  }
]


Good, I found some tweets. Let me look at these options:

1. Austin894742999 - J-B Weld deal - seems like a deal bot, not a real person
2. CentralMarkdown - Stanley water bottle deal - also looks like a deal account/bot
3. wasim_asad - Smart Finance App - self-promotion for their app
4. Austin894742999 - VEVOR wagon cart - deal bot
5. Austin894742999 - adidas socks - deal bot

These are all deal bots or self-promotion. Let me search with different hashtags to find real people. Let me check other search scripts or search with different terms.

The tweets I found are mostly from deal bots. Let me search with different hashtags to find real people sharing genuine experiences:

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && cat search_authentic_personal.mjs


#!/usr/bin/env node
/**
 * Find authentic tweets for engagement - GHC profile
 */

import { chromium } from 'playwright-extra';
import stealthPlugin from 'puppeteer-extra-plugin-stealth';
import { execSync } from 'child_process';
import fs from 'fs';

chromium.use(stealthPlugin());

const PROFILE = '/home/crogers2287/.social-poster-profile-ghc';

// Start Xvfb
process.env.DISPLAY = ':100';

const browser = await chromium.launchPersistentContext(PROFILE, {
  headless: false,
  viewport: { width: 1920, height: 1080 },
  args: ['--no-sandbox', '--disable-blink-features=AutomationControlled', '--display=:100'],
  ignoreDefaultArgs: ['--enable-automation'],
});

const page = browser.pages()[0] || await browser.newPage();

// Search for personal finance/frugal tweets
const searchQueries = [
  '#savemoney tips',
  'couponing help',
  'frugal living advice',
  'budget tips',
  'saving money advice'
];

const cutoff = new Date(Date.now() - 48 * 60 * 60 * 1000);
const allTweets = [];

for (const query of searchQueries) {
  try {
    console.log(`[+] Searching: ${query}`);
    await page.goto(`https://x.com/search?q=${encodeURIComponent(query)}&src=typed_query&f=live`, {
      waitUntil: 'domcontentloaded',
      timeout: 30000
    });
    await page.waitForTimeout(3000);

    const tweets = await page.$$eval('article[data-testid="tweet"]', (articles, cutoffStr) => {
      const cutoff = new Date(cutoffStr);
      return articles.map(article => {
        const textEl = article.querySelector('[data-testid="tweetText"]');
        const timeEl = article.querySelector('time');
        const linkEl = article.querySelector('a[href*="/status/"]');
        const userEl = article.querySelector('[data-testid="User-Name"]');

        const text = textEl ? textEl.innerText : '';
        const time = timeEl ? timeEl.getAttribute('datetime') : '';
        const url = linkEl ? 'https://x.com' + linkEl.getAttribute('href') : '';
        const userHtml = userEl ? userEl.innerText : '';
        const user = userHtml.split('\n')[0];
        const handle = userHtml.split('\n')[1] || '';

        // Check if recent
        const tweetTime = time ? new Date(time) : null;
        const isRecent = tweetTime && tweetTime > cutoff;

        // Skip likely bots/spam
        const isLikelyBot = text.includes('*ad') ||
                           text.includes('Check it out:') ||
                           text.includes('utm_source=') ||
                           text.startsWith('http') ||
                           user.toLowerCase().includes('deal');

        return { text: text.substring(0, 300), time, url, user, handle, isRecent, isLikelyBot };
      }).filter(t => t.isRecent && t.text.length > 20 && !t.isLikelyBot);
    }, cutoff.toISOString());

    allTweets.push(...tweets);
  } catch (e) {
    console.log(`Search error for ${query}:`, e.message);
  }
}

// Remove duplicates
const unique = [];
const seen = new Set();
for (const t of allTweets) {
  if (!seen.has(t.url) && t.url) {
    seen.add(t.url);
    unique.push(t);
  }
}

console.log('\n=== Authentic Tweets Found ===\n');
console.log(JSON.stringify(unique.slice(0, 10), null, 2));

fs.writeFileSync('/tmp/authentic_tweets.json', JSON.stringify(unique.slice(0, 10), null, 2));
console.log('\n[+] Saved to /tmp/authentic_tweets.json');

await browser.close();


Let me run this script to find more authentic tweets.

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" node search_authentic_personal.mjs


Command still running (session crisp-orbit, pid 2954028). Use process (list/poll/log/write/kill/clear/remove) for follow-up.

[+] Searching: #savemoney tips
[+] Searching: couponing help


The command is taking a while. Let me check on it.


[+] Searching: #savemoney tips
[+] Searching: couponing help
[+] Searching: frugal living advice

Process still running.


Let me wait a bit more for this to complete.


[+] Searching: budget tips

Process still running.

[+] Searching: #savemoney tips
[+] Searching: couponing help
[+] Searching: frugal living advice
[+] Searching: budget tips


(no new output)

Process still running.


Let me check the log to see if there's more output or if it's stuck.


[+] Searching: #savemoney tips
[+] Searching: couponing help
[+] Searching: frugal living advice
[+] Searching: budget tips
[+] Searching: saving money advice


It seems to have completed the searches but may be hanging on closing the browser or something. Let me wait a bit longer.


[+] Searching: saving money advice

Process still running.

[+] Searching: #savemoney tips
[+] Searching: couponing help
[+] Searching: frugal living advice
[+] Searching: budget tips
[+] Searching: saving money advice


It's stuck. Let me kill it and try a different approach - maybe using the simple_search script or searching directly in the browser.


Killed session crisp-orbit.


Let me try the simple_search script which might be faster.

cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && cat simple_search.mjs


#!/usr/bin/env node
/**
 * Simple X search for engagement - GHC profile
 */

import { chromium } from 'playwright-extra';
import stealthPlugin from 'puppeteer-extra-plugin-stealth';
import { execSync } from 'child_process';

chromium.use(stealthPlugin());

const PROFILE = '/home/crogers2287/.social-poster-profile-ghc';

// Start Xvfb
try { execSync('pgrep -f "Xvfb :99"', { stdio: 'ignore' }); } catch {
  execSync('Xvfb :99 -screen 0 1920x1080x24 &', { stdio: 'ignore' });
  execSync('sleep 1');
}
process.env.DISPLAY = ':99';

const browser = await chromium.launchPersistentContext(PROFILE, {
  headless: false,
  viewport: { width: 1920, height: 1080 },
  args: ['--no-sandbox', '--disable-blink-features=AutomationControlled', '--display=:99'],
  ignoreDefaultArgs: ['--enable-automation'],
});

const page = browser.pages()[0] || await browser.newPage();

// Go to X home to verify login
await page.goto('https://x.com/home', { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForTimeout(2000);

const url = page.url();
const loggedIn = !url.includes('/login') && !url.includes('/i/flow');
console.log('Logged in:', loggedIn);

if (!loggedIn) {
  console.log('ERROR: Not logged in! Current URL:', url);
  await browser.close();
  process.exit(1);
}

// Search for recent tweets
console.log('[+] Searching for recent tweets...');
const searchQueries = [
  '#savemoney',
  '#couponing',
  '#frugalliving',
  '#deals',
  '#budgettips'
];

const cutoff = new Date(Date.now() - 48 * 60 * 60 * 1000); // 48 hours ago
const allTweets = [];

for (const query of searchQueries) {
  try {
    await page.goto(`https://x.com/search?q=${encodeURIComponent(query)}&src=typed_query&f=live`, {
      waitUntil: 'domcontentloaded',
      timeout: 30000
    });
    await page.waitForTimeout(4000);

    const tweets = await page.$$eval('article[data-testid="tweet"]', (articles, cutoffStr) => {
      const cutoff = new Date(cutoffStr);
      return articles.map(article => {
        const textEl = article.querySelector('[data-testid="tweetText"]');
        const timeEl = article.querySelector('time');
        const linkEl = article.querySelector('a[href*="/status/"]');
        const userEl = article.querySelector('[data-testid="User-Name"]');

        const text = textEl ? textEl.innerText : '';
        const time = timeEl ? timeEl.getAttribute('datetime') : '';
        const url = linkEl ? 'https://x.com' + linkEl.getAttribute('href') : '';
        const user = userEl ? userEl.innerText.split('\n')[0] : '';

        // Check if recent
        const tweetTime = time ? new Date(time) : null;
        const isRecent = tweetTime && tweetTime > cutoff;

        return { text, time, url, user, isRecent };
      }).filter(t => t.isRecent && t.text.length > 20);
    }, cutoff.toISOString());

    allTweets.push(...tweets);
  } catch (e) {
    console.log(`Search error for ${query}:`, e.message);
  }
}

// Remove duplicates
const unique = [];
const seen = new Set();
for (const t of allTweets) {
  if (!seen.has(t.url)) {
    seen.add(t.url);
    unique.push(t);
  }
}

console.log(JSON.stringify(unique.slice(0, 10), null, 2));
await browser.close();


cd /home/crogers2287/openclaw-workspaces/cannadeals-marketing/skills/social-poster && xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" node simple_search.mjs


Command still running (session fresh-ember, pid 2959446). Use process (list/poll/log/write/kill/clear/remove) for follow-up.

Logged in: true
[+] Searching for recent tweets...


Logged in: true
[+] Searching for recent tweets...

Process still running.


Good, it's logged in and searching. Let me wait for it to complete.


Logged in: true
[+] Searching for recent tweets...