chore(cli): save screenshots to tmp dir when no path provided (#247)
* fix(cli): save screenshots to tmp dir when no path provided Instead of outputting base64 to stdout (which is not useful for most CLI use cases), screenshots without a path now save to ~/.agent-browser/tmp/screenshots/ with a generated filename and return the path. This makes the behavior more ergonomic for AI agents and CLI users alike. * cleanup * cleanup * just revert the cargo.lock version for now * refactor: extract getAppDir() from getSocketDir() * docs: improve screenshot help text consistency
This commit is contained in:
@@ -74,7 +74,7 @@ agent-browser scroll <dir> [px] # Scroll (up/down/left/right)
|
|||||||
agent-browser scrollintoview <sel> # Scroll element into view (alias: scrollinto)
|
agent-browser scrollintoview <sel> # Scroll element into view (alias: scrollinto)
|
||||||
agent-browser drag <src> <tgt> # Drag and drop
|
agent-browser drag <src> <tgt> # Drag and drop
|
||||||
agent-browser upload <sel> <files> # Upload files
|
agent-browser upload <sel> <files> # Upload files
|
||||||
agent-browser screenshot [path] # Take screenshot (--full for full page, base64 png to stdout if no path)
|
agent-browser screenshot [path] # Take screenshot (--full for full page, saves to a temporary directory if no path)
|
||||||
agent-browser pdf <path> # Save as PDF
|
agent-browser pdf <path> # Save as PDF
|
||||||
agent-browser snapshot # Accessibility tree with refs (best for AI)
|
agent-browser snapshot # Accessibility tree with refs (best for AI)
|
||||||
agent-browser eval <js> # Run JavaScript
|
agent-browser eval <js> # Run JavaScript
|
||||||
|
|||||||
+1
-6
@@ -280,11 +280,6 @@ pub fn print_response(resp: &Response, json_mode: bool, action: Option<&str>) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Screenshot base64
|
|
||||||
if let Some(base64) = data.get("base64").and_then(|v| v.as_str()) {
|
|
||||||
println!("{}", base64);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Path-based operations (screenshot/pdf/trace/har/download/state/video)
|
// Path-based operations (screenshot/pdf/trace/har/download/state/video)
|
||||||
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
if let Some(path) = data.get("path").and_then(|v| v.as_str()) {
|
||||||
match action.unwrap_or("") {
|
match action.unwrap_or("") {
|
||||||
@@ -817,7 +812,7 @@ agent-browser screenshot - Take a screenshot
|
|||||||
Usage: agent-browser screenshot [path]
|
Usage: agent-browser screenshot [path]
|
||||||
|
|
||||||
Captures a screenshot of the current page. If no path is provided,
|
Captures a screenshot of the current page. If no path is provided,
|
||||||
outputs base64-encoded image data.
|
saves to a temporary directory with a generated filename.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--full, -f Capture full page (not just viewport)
|
--full, -f Capture full page (not just viewport)
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ agent-browser snapshot # Get accessibility tree with refs
|
|||||||
agent-browser click @e2 # Click by ref from snapshot
|
agent-browser click @e2 # Click by ref from snapshot
|
||||||
agent-browser fill @e3 "test@example.com" # Fill by ref
|
agent-browser fill @e3 "test@example.com" # Fill by ref
|
||||||
agent-browser get text @e1 # Get text by ref
|
agent-browser get text @e1 # Get text by ref
|
||||||
agent-browser screenshot # Base64 png to stdout
|
agent-browser screenshot # Save to a temporary directory
|
||||||
agent-browser screenshot page.png # Save to file
|
agent-browser screenshot page.png # Save to a specific path
|
||||||
agent-browser close`} />
|
agent-browser close`} />
|
||||||
|
|
||||||
<h2>Traditional selectors</h2>
|
<h2>Traditional selectors</h2>
|
||||||
|
|||||||
@@ -96,8 +96,8 @@ agent-browser is checked @e1 # Check if checked
|
|||||||
### Screenshots & PDF
|
### Screenshots & PDF
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-browser screenshot # Screenshot to stdout
|
agent-browser screenshot # Save to a temporary directory
|
||||||
agent-browser screenshot path.png # Save to file
|
agent-browser screenshot path.png # Save to a specific path
|
||||||
agent-browser screenshot --full # Full page
|
agent-browser screenshot --full # Full page
|
||||||
agent-browser pdf output.pdf # Save as PDF
|
agent-browser pdf output.pdf # Save as PDF
|
||||||
```
|
```
|
||||||
|
|||||||
+15
-6
@@ -1,5 +1,8 @@
|
|||||||
import type { Page, Frame } from 'playwright-core';
|
import type { Page, Frame } from 'playwright-core';
|
||||||
|
import { mkdirSync } from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
import type { BrowserManager, ScreencastFrame } from './browser.js';
|
import type { BrowserManager, ScreencastFrame } from './browser.js';
|
||||||
|
import { getAppDir } from './daemon.js';
|
||||||
import type {
|
import type {
|
||||||
Command,
|
Command,
|
||||||
Response,
|
Response,
|
||||||
@@ -561,13 +564,19 @@ async function handleScreenshot(
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (command.path) {
|
let savePath = command.path;
|
||||||
await target.screenshot({ ...options, path: command.path });
|
if (!savePath) {
|
||||||
return successResponse(command.id, { path: command.path });
|
const ext = command.format === 'jpeg' ? 'jpg' : 'png';
|
||||||
} else {
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
const buffer = await target.screenshot(options);
|
const random = Math.random().toString(36).substring(2, 8);
|
||||||
return successResponse(command.id, { base64: buffer.toString('base64') });
|
const filename = `screenshot-${timestamp}-${random}.${ext}`;
|
||||||
|
const screenshotDir = path.join(getAppDir(), 'tmp', 'screenshots');
|
||||||
|
mkdirSync(screenshotDir, { recursive: true });
|
||||||
|
savePath = path.join(screenshotDir, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await target.screenshot({ ...options, path: savePath });
|
||||||
|
return successResponse(command.id, { path: savePath });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (command.selector) {
|
if (command.selector) {
|
||||||
throw toAIFriendlyError(error, command.selector);
|
throw toAIFriendlyError(error, command.selector);
|
||||||
|
|||||||
+12
-9
@@ -51,27 +51,30 @@ function getPortForSession(session: string): number {
|
|||||||
* Get the base directory for socket/pid files.
|
* Get the base directory for socket/pid files.
|
||||||
* Priority: AGENT_BROWSER_SOCKET_DIR > XDG_RUNTIME_DIR > ~/.agent-browser > tmpdir
|
* Priority: AGENT_BROWSER_SOCKET_DIR > XDG_RUNTIME_DIR > ~/.agent-browser > tmpdir
|
||||||
*/
|
*/
|
||||||
export function getSocketDir(): string {
|
export function getAppDir(): string {
|
||||||
// 1. Explicit override
|
// 1. XDG_RUNTIME_DIR (Linux standard)
|
||||||
if (process.env.AGENT_BROWSER_SOCKET_DIR) {
|
|
||||||
return process.env.AGENT_BROWSER_SOCKET_DIR;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. XDG_RUNTIME_DIR (Linux standard)
|
|
||||||
if (process.env.XDG_RUNTIME_DIR) {
|
if (process.env.XDG_RUNTIME_DIR) {
|
||||||
return path.join(process.env.XDG_RUNTIME_DIR, 'agent-browser');
|
return path.join(process.env.XDG_RUNTIME_DIR, 'agent-browser');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Home directory fallback (like Docker Desktop's ~/.docker/run/)
|
// 2. Home directory fallback (like Docker Desktop's ~/.docker/run/)
|
||||||
const homeDir = os.homedir();
|
const homeDir = os.homedir();
|
||||||
if (homeDir) {
|
if (homeDir) {
|
||||||
return path.join(homeDir, '.agent-browser');
|
return path.join(homeDir, '.agent-browser');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Last resort: temp dir
|
// 3. Last resort: temp dir
|
||||||
return path.join(os.tmpdir(), 'agent-browser');
|
return path.join(os.tmpdir(), 'agent-browser');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSocketDir(): string {
|
||||||
|
// Allow explicit override for socket directory
|
||||||
|
if (process.env.AGENT_BROWSER_SOCKET_DIR) {
|
||||||
|
return process.env.AGENT_BROWSER_SOCKET_DIR;
|
||||||
|
}
|
||||||
|
return getAppDir();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the socket path for the current session (Unix) or port (Windows)
|
* Get the socket path for the current session (Unix) or port (Windows)
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user