← back to Adsense Fleet Viewer
verification/TK-11352-health/status-before.mjs
62 lines
#!/usr/bin/env node
// AdSense approval-status poller — reads the live console sites list via the
// openclaw (Steve's real Chrome, already signed in) and extracts each of our
// domains' approval + ads.txt status. Best-effort: if openclaw/session is
// unavailable it writes UNKNOWN rather than a false state. Output: data/status-latest.json
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const SKILL = path.join(__dirname, '..');
const FLEET = '/Users/macstudio3/Projects/dw-domain-fleet/sites';
const LIST = 'https://adsense.google.com/adsense/u/0/pub-5278231299883833/sites/list';
const TARGET = process.env.ADSENSE_BROWSER_TARGET || '';
const ours = new Set(fs.readdirSync(FLEET).filter(f => f.endsWith('.json'))
.map(f => { try { return JSON.parse(fs.readFileSync(path.join(FLEET, f), 'utf8')); } catch { return null; } })
.filter(s => s && s.monetize === true).map(s => s.domain));
function oc(args) { return execSync(`openclaw ${args}`, { encoding: 'utf8', timeout: 30000, stdio: ['ignore', 'pipe', 'ignore'] }); }
let rows = [], ok = false, complete = false, expectedConsoleCount = null;
try {
if (!/^[A-Za-z0-9_-]+$/.test(TARGET)) throw new Error('ADSENSE_BROWSER_TARGET is required for isolated console reads');
const st = JSON.parse(oc('browser status --json 2>/dev/null') || '{}');
if (st.running) {
oc(`browser navigate ${JSON.stringify(LIST)} --target-id ${TARGET} >/dev/null 2>&1`);
execSync('sleep 3');
// Parse the sites table innerText into {domain, status, adstxt}
const fn = "() => { const t=document.body.innerText; const lines=t.split('\\n').map(x=>x.trim()).filter(Boolean); const out=[]; for(let i=0;i<lines.length;i++){ if(/^[a-z0-9.-]+\\.(com|net|org|ai)$/i.test(lines[i])){ const dom=lines[i]; const win=lines.slice(i+1,i+5).join(' | '); out.push({dom, win}); } } const m=t.match(/\\bof\\s+(\\d+)\\b/i); return {rows:out,total:m?Number(m[1]):null}; }";
const raw = oc(`browser evaluate --target-id ${TARGET} --fn ${JSON.stringify(fn)} 2>/dev/null`);
const parsedObj = JSON.parse(raw.slice(raw.indexOf('{')));
const parsed = parsedObj.rows || [];
const consoleTotal = Number.isFinite(parsedObj.total) ? parsedObj.total : null;
const statusRe = /\b(Ready|Getting ready|Requires review|Needs attention)\b/i;
// "Getting ready" is an approval state, never an ads.txt state. The
// previous combined-window parser reported it as ads.txt and hid Not found.
const adsRe = /\b(Authorized|Not found|Unauthorized)\b/i;
const seen = new Set();
for (const p of parsed) {
if (seen.has(p.dom)) continue;
seen.add(p.dom);
rows.push({ domain: p.dom, approval: (p.win.match(statusRe) || [,'UNKNOWN'])[1], ads_txt: (p.win.match(adsRe) || [,'UNKNOWN'])[1] });
}
complete = rows.length >= (consoleTotal || ours.size) && !rows.some(r => r.approval === 'UNKNOWN' || r.ads_txt === 'UNKNOWN');
if (consoleTotal) expectedConsoleCount = consoleTotal;
ok = rows.length > 0;
}
} catch (e) { /* fall through to UNKNOWN */ }
// fill any of ours we didn't see as UNKNOWN
for (const d of ours) if (!rows.find(r => r.domain === d)) rows.push({ domain: d, approval: 'UNKNOWN', ads_txt: 'UNKNOWN' });
rows.sort((a, b) => a.domain.localeCompare(b.domain));
const tally = rows.reduce((m, r) => (m[r.approval] = (m[r.approval] || 0) + 1, m), {});
const out = { ts: new Date().toISOString(), source: ok ? 'openclaw-console' : 'unavailable', complete, expected_count: expectedConsoleCount || ours.size, count: rows.length, tally, rows };
fs.mkdirSync(path.join(SKILL, 'data'), { recursive: true });
fs.writeFileSync(path.join(SKILL, 'data', 'status-latest.json'), JSON.stringify(out, null, 2));
console.log(`AdSense status (${out.source}) — ${JSON.stringify(tally)}`);
if (rows.some(r => r.approval === 'Ready')) console.log('APPROVED:', rows.filter(r => r.approval === 'Ready').map(r => r.domain).join(', '));