feat: network idle detection + chain pipe format

- Upgrade click/fill/select from domcontentloaded to networkidle wait
  (2s timeout, best-effort). Catches XHR/fetch triggered by interactions.
- Add pipe-delimited format to chain as JSON fallback:
  $B chain 'goto url | click @e5 | snapshot -ic'
- Add post-loop networkidle wait in chain when last command was a write.
- Frame-aware: commands use target (getActiveFrameOrPage) for locator ops,
  page-only ops (goto/back/forward/reload) guard against frame context.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-26 00:46:51 -06:00
parent 9daf33c84b
commit e497d996c5
3 changed files with 150 additions and 27 deletions

View File

@@ -1323,13 +1323,12 @@ describe('Errors', () => {
}
});
test('chain with invalid JSON throws', async () => {
try {
await handleMetaCommand('chain', ['not json'], bm, async () => {});
expect(true).toBe(false);
} catch (err: any) {
expect(err.message).toContain('Invalid JSON');
}
test('chain with invalid JSON falls back to pipe format', async () => {
// Non-JSON input is now treated as pipe-delimited format
// 'not json' → [["not", "json"]] → "not" is unknown command → error in result
const result = await handleMetaCommand('chain', ['not json'], bm, async () => {});
expect(result).toContain('ERROR');
expect(result).toContain('Unknown command: not');
});
test('chain with no arg throws', async () => {