Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- `--max-field-length <N>` flag for `extract` macro to configure maximum characters per extracted field (default: 500, max: 2000)

### Fixed
- Smart default snapshot scoping now includes complementary ARIA landmarks (`<aside>`, `[role="complementary"]`) alongside `<main>`, capturing sidebar content like repository stats (#26)
- `extract` auto-detect `buildSelector` no longer produces double ` > > ` combinators in CSS selectors (#52)
- `extract` auto-detect `buildSelector` skips auto-generated IDs (numeric, hex strings, framework prefixes like `ext-`, `ember`, `ng-`, patterns with `:` or `.`) and anchors on stable human-readable IDs instead, making detected selectors reusable across page reloads (#52)
- Auth success detection no longer triggers false positives when the login page URL matches the successUrl pattern (e.g. Instagram, Reddit, Facebook whose login pages are sub-paths of the site root) (#40)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ This eliminates the common click-snapshot-check loop that wastes agent turns on
| `--snapshot-collapse` | Any action with snapshot | Collapse repeated siblings (keep first 2, summarize rest) |
| `--snapshot-text-only` | Any action with snapshot | Strip structural nodes, keep content only |
| `--max-field-length <N>` | `extract` | Max characters per field (default: 500, max: 2000) |
| `--snapshot-full` | Any action with snapshot | Use full page body (default: auto-scope to `<main>` content area) |
| `--snapshot-full` | Any action with snapshot | Use full page body (default: auto-scope to `<main>` and complementary landmarks) |
| `--no-snapshot` | Any action with snapshot | Omit snapshot from output entirely |

## Error Handling
Expand Down
37 changes: 34 additions & 3 deletions scripts/web-ctl.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,48 @@ function resolveSelector(page, selector) {
/**
* Detect the main content area of the page.
* Tries <main>, then [role="main"], then falls back to <body>.
* When a main landmark is found, also captures adjacent complementary
* landmarks (aside, [role="complementary"]) and returns a virtual locator
* whose ariaSnapshot() concatenates all regions.
*
* @param {object} page - Playwright page object
* @returns {object} Playwright locator for the main content area
* @returns {object} Playwright locator (or virtual locator) for the main content area
*/
async function detectMainContent(page) {
try {
const mainTag = page.locator('main').first();
const mainRole = page.locator('[role="main"]').first();
const [mainCount, roleCount] = await Promise.all([mainTag.count(), mainRole.count()]);
if (mainCount > 0) return mainTag;
if (roleCount > 0) return mainRole;

let mainLocator = null;
let compSelector = null;
if (mainCount > 0) {
mainLocator = mainTag;
compSelector = 'main ~ aside, main ~ [role="complementary"]';
} else if (roleCount > 0) {
mainLocator = mainRole;
compSelector = '[role="main"] ~ aside, [role="main"] ~ [role="complementary"]';
}

if (mainLocator) {
try {
const compLocator = page.locator(compSelector);
const compCount = await compLocator.count();
if (compCount > 0) {
const cap = Math.min(compCount, 3);
return {
ariaSnapshot: async () => {
const parts = [await mainLocator.ariaSnapshot()];
await Promise.all(Array.from({ length: cap }, (_, i) =>
compLocator.nth(i).ariaSnapshot().then(s => { parts[i + 1] = s; }).catch(() => {})
));
return parts.filter(Boolean).join('\n');
}
};
}
} catch { /* complementary detection failed, return main only */ }
return mainLocator;
}
} catch {
// fall through to body
}
Expand Down
2 changes: 1 addition & 1 deletion skills/web-browse/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ Auto-detect mode also returns the detected CSS selector, which can be reused wit

All actions that return a snapshot support these flags to control output size.

By default, snapshots are auto-scoped to the main content area of the page. The tool looks for a `<main>` element, then `[role="main"]`, and falls back to `<body>` if neither exists. This automatically excludes navigation, headers, and footers from snapshots, reducing noise and token usage. Use `--snapshot-full` to capture the full page body when needed, or `--snapshot-selector` to scope to a specific element.
By default, snapshots are auto-scoped to the main content area of the page. The tool looks for a `<main>` element, then `[role="main"]`, and falls back to `<body>` if neither exists. When a main landmark is found, adjacent complementary landmarks (`<aside>`, `[role="complementary"]`) are also included - this captures sidebar content like repository stats without requiring manual scoping. This automatically excludes navigation, headers, and footers from snapshots, reducing noise and token usage. Use `--snapshot-full` to capture the full page body when needed, or `--snapshot-selector` to scope to a specific element.

### --snapshot-depth N - Limit Tree Depth

Expand Down
Loading
Loading