mirror of https://github.com/garrytan/gstack.git
feat: add screenshot --base64 for inline image return
Returns data:image/png;base64,... instead of writing to disk. Cap at 10MB. Works with all screenshot modes (element, clip, viewport). Eliminates the two-step screenshot+file-serve dance for remote agents. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ae3c7d1f54
commit
511419fb85
|
|
@ -112,17 +112,20 @@ export async function handleMetaCommand(
|
||||||
|
|
||||||
// ─── Visual ────────────────────────────────────────
|
// ─── Visual ────────────────────────────────────────
|
||||||
case 'screenshot': {
|
case 'screenshot': {
|
||||||
// Parse priority: flags (--viewport, --clip) → selector (@ref, CSS) → output path
|
// Parse priority: flags (--viewport, --clip, --base64) → selector (@ref, CSS) → output path
|
||||||
const page = bm.getPage();
|
const page = bm.getPage();
|
||||||
let outputPath = `${TEMP_DIR}/browse-screenshot.png`;
|
let outputPath = `${TEMP_DIR}/browse-screenshot.png`;
|
||||||
let clipRect: { x: number; y: number; width: number; height: number } | undefined;
|
let clipRect: { x: number; y: number; width: number; height: number } | undefined;
|
||||||
let targetSelector: string | undefined;
|
let targetSelector: string | undefined;
|
||||||
let viewportOnly = false;
|
let viewportOnly = false;
|
||||||
|
let base64Mode = false;
|
||||||
|
|
||||||
const remaining: string[] = [];
|
const remaining: string[] = [];
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (let i = 0; i < args.length; i++) {
|
||||||
if (args[i] === '--viewport') {
|
if (args[i] === '--viewport') {
|
||||||
viewportOnly = true;
|
viewportOnly = true;
|
||||||
|
} else if (args[i] === '--base64') {
|
||||||
|
base64Mode = true;
|
||||||
} else if (args[i] === '--clip') {
|
} else if (args[i] === '--clip') {
|
||||||
const coords = args[++i];
|
const coords = args[++i];
|
||||||
if (!coords) throw new Error('Usage: screenshot --clip x,y,w,h [path]');
|
if (!coords) throw new Error('Usage: screenshot --clip x,y,w,h [path]');
|
||||||
|
|
@ -159,6 +162,24 @@ export async function handleMetaCommand(
|
||||||
throw new Error('Cannot use --viewport with --clip — choose one');
|
throw new Error('Cannot use --viewport with --clip — choose one');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --base64 mode: capture to buffer instead of disk
|
||||||
|
if (base64Mode) {
|
||||||
|
let buffer: Buffer;
|
||||||
|
if (targetSelector) {
|
||||||
|
const resolved = await bm.resolveRef(targetSelector);
|
||||||
|
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
|
||||||
|
buffer = await locator.screenshot({ timeout: 5000 });
|
||||||
|
} else if (clipRect) {
|
||||||
|
buffer = await page.screenshot({ clip: clipRect });
|
||||||
|
} else {
|
||||||
|
buffer = await page.screenshot({ fullPage: !viewportOnly });
|
||||||
|
}
|
||||||
|
if (buffer.length > 10 * 1024 * 1024) {
|
||||||
|
throw new Error('Screenshot too large for --base64 (>10MB). Use disk path instead.');
|
||||||
|
}
|
||||||
|
return `data:image/png;base64,${buffer.toString('base64')}`;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetSelector) {
|
if (targetSelector) {
|
||||||
const resolved = await bm.resolveRef(targetSelector);
|
const resolved = await bm.resolveRef(targetSelector);
|
||||||
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
|
const locator = 'locator' in resolved ? resolved.locator : page.locator(resolved.selector);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue