From e8a6ada2d62af3e758f9077e53845c2067ca9179 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 8 Jul 2026 00:59:39 +0000 Subject: [PATCH] Add ChatGPT share debug helper --- Dockerfile | 1 + scripts/debug-chatgpt-share.mjs | 87 +++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 scripts/debug-chatgpt-share.mjs diff --git a/Dockerfile b/Dockerfile index 19526bd..a63c2e1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,6 +25,7 @@ RUN apt-get update \ COPY --from=build /app/node_modules ./node_modules COPY --from=build /app/dist ./dist COPY --from=build /app/dist-client ./dist-client +COPY scripts ./scripts COPY package.json ./ RUN ./node_modules/.bin/playwright install --with-deps --only-shell chromium \ && npm cache clean --force \ diff --git a/scripts/debug-chatgpt-share.mjs b/scripts/debug-chatgpt-share.mjs new file mode 100644 index 0000000..ceb5406 --- /dev/null +++ b/scripts/debug-chatgpt-share.mjs @@ -0,0 +1,87 @@ +import { chromium } from "playwright"; + +const sourceUrl = process.argv[2]; +const holdMs = Number(process.env.DEBUG_HOLD_MS || "900000"); +const port = Number(process.env.DEBUG_PORT || "9222"); + +if (!sourceUrl) { + console.error("usage: node scripts/debug-chatgpt-share.mjs "); + process.exit(2); +} + +let browser; +let context; + +function now() { + return new Date().toISOString(); +} + +async function close() { + if (context) await context.close().catch(() => undefined); + if (browser) await browser.close().catch(() => undefined); +} + +process.on("SIGINT", () => close().finally(() => process.exit(130))); +process.on("SIGTERM", () => close().finally(() => process.exit(143))); + +browser = await chromium.launch({ + headless: true, + args: [ + `--remote-debugging-address=0.0.0.0`, + `--remote-debugging-port=${port}` + ] +}); + +context = await browser.newContext({ + viewport: { width: 1360, height: 900 }, + deviceScaleFactor: 1, + locale: "en-US" +}); + +const page = await context.newPage(); +page.setDefaultTimeout(30_000); + +console.log(`[${now()}] Chromium DevTools port: ${port}`); +console.log(`[${now()}] Opening ${sourceUrl}`); + +await page.goto(sourceUrl, { waitUntil: "domcontentloaded", timeout: 45_000 }); +await page.waitForLoadState("networkidle", { timeout: 20_000 }).catch(() => undefined); +await page.waitForTimeout(3000); + +const summary = await page.evaluate(() => { + const selectors = [ + "[data-message-author-role]", + "[data-message-id]", + "[data-testid]", + "main article", + "main [role=listitem]", + "main .markdown", + "main [class*=markdown]", + "script[type='application/json']", + "script#__NEXT_DATA__" + ]; + + const counts = Object.fromEntries(selectors.map((selector) => [selector, document.querySelectorAll(selector).length])); + const title = document.querySelector("h1")?.textContent?.trim() || document.title; + const bodySample = (document.body.textContent || "").replace(/\s+/g, " ").trim().slice(0, 600); + const testIds = Array.from(document.querySelectorAll("[data-testid]")) + .map((element) => element.getAttribute("data-testid")) + .filter(Boolean) + .slice(0, 80); + + return { + href: location.href, + title, + counts, + testIds, + bodySample + }; +}); + +console.log(JSON.stringify(summary, null, 2)); +console.log(`[${now()}] Holding browser for ${Math.round(holdMs / 1000)}s.`); +console.log(`[${now()}] Tunnel with: ssh -L ${port}:127.0.0.1:${port} titan-reverse`); +console.log(`[${now()}] Then open: chrome://inspect/#devices`); + +await new Promise((resolve) => setTimeout(resolve, holdMs)); +await close();