mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
feat: add authenticated screenshot utility for Paperclip UI
Reads board token from ~/.paperclip/auth.json and injects it as a Bearer header via Playwright, enabling agents to take screenshots of authenticated pages without storing email/password credentials. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
ebc6888e7d
commit
5d0db75ba3
1 file changed
+86
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Screenshot utility for Paperclip UI.
|
||||
*
|
||||
* Reads the board token from ~/.paperclip/auth.json and injects it as a
|
||||
* Bearer header so Playwright can access authenticated pages.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/screenshot.cjs <url-or-path> [output.png] [--width 1280] [--height 800] [--wait 2000]
|
||||
*
|
||||
* Examples:
|
||||
* node scripts/screenshot.cjs /PAPA/agents/cto/instructions /tmp/shot.png
|
||||
* node scripts/screenshot.cjs http://localhost:5173/PAPA/agents/cto/instructions
|
||||
*/
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const os = require("os");
|
||||
|
||||
// --- CLI args -----------------------------------------------------------
|
||||
const args = process.argv.slice(2);
|
||||
function flag(name, fallback) {
|
||||
const i = args.indexOf(`--${name}`);
|
||||
if (i === -1) return fallback;
|
||||
const val = args.splice(i, 2)[1];
|
||||
return Number(val) || fallback;
|
||||
}
|
||||
const width = flag("width", 1280);
|
||||
const height = flag("height", 800);
|
||||
const waitMs = flag("wait", 2000);
|
||||
|
||||
const rawUrl = args[0];
|
||||
const outPath = args[1] || "/tmp/paperclip-screenshot.png";
|
||||
|
||||
if (!rawUrl) {
|
||||
console.error("Usage: node scripts/screenshot.cjs <url-or-path> [output.png]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// --- Auth ----------------------------------------------------------------
|
||||
function loadBoardToken() {
|
||||
const authPath = path.resolve(os.homedir(), ".paperclip/auth.json");
|
||||
try {
|
||||
const auth = JSON.parse(fs.readFileSync(authPath, "utf-8"));
|
||||
const creds = auth.credentials || {};
|
||||
const entry = Object.values(creds)[0];
|
||||
if (entry && entry.token) return { token: entry.token, apiBase: entry.apiBase };
|
||||
} catch (_) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const cred = loadBoardToken();
|
||||
if (!cred) {
|
||||
console.error("No board token found in ~/.paperclip/auth.json");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Resolve URL — if it starts with / treat as path relative to apiBase
|
||||
const url = rawUrl.startsWith("http") ? rawUrl : `${cred.apiBase}${rawUrl}`;
|
||||
|
||||
// --- Screenshot ----------------------------------------------------------
|
||||
(async () => {
|
||||
const { chromium } = require("playwright");
|
||||
const browser = await chromium.launch();
|
||||
const context = await browser.newContext({
|
||||
viewport: { width, height },
|
||||
extraHTTPHeaders: {
|
||||
Authorization: `Bearer ${cred.token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const page = await context.newPage();
|
||||
try {
|
||||
await page.goto(url, { waitUntil: "networkidle", timeout: 20000 });
|
||||
await page.waitForTimeout(waitMs);
|
||||
await page.screenshot({ path: outPath, fullPage: false });
|
||||
console.log(`Saved: ${outPath}`);
|
||||
} catch (err) {
|
||||
console.error(`Screenshot failed: ${err.message}`);
|
||||
process.exit(1);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
})();
|
||||
Reference in new issue
Block a user