sentienceapi 0.92.3 → 0.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +125 -54
  2. package/dist/agent-runtime.d.ts +190 -0
  3. package/dist/agent-runtime.d.ts.map +1 -0
  4. package/dist/agent-runtime.js +257 -0
  5. package/dist/agent-runtime.js.map +1 -0
  6. package/dist/asserts/expect.d.ts +159 -0
  7. package/dist/asserts/expect.d.ts.map +1 -0
  8. package/dist/asserts/expect.js +547 -0
  9. package/dist/asserts/expect.js.map +1 -0
  10. package/dist/asserts/index.d.ts +58 -0
  11. package/dist/asserts/index.d.ts.map +1 -0
  12. package/dist/asserts/index.js +70 -0
  13. package/dist/asserts/index.js.map +1 -0
  14. package/dist/asserts/query.d.ts +199 -0
  15. package/dist/asserts/query.d.ts.map +1 -0
  16. package/dist/asserts/query.js +288 -0
  17. package/dist/asserts/query.js.map +1 -0
  18. package/dist/backends/actions.d.ts +118 -0
  19. package/dist/backends/actions.d.ts.map +1 -0
  20. package/dist/backends/actions.js +262 -0
  21. package/dist/backends/actions.js.map +1 -0
  22. package/dist/backends/browser-use-adapter.d.ts +131 -0
  23. package/dist/backends/browser-use-adapter.d.ts.map +1 -0
  24. package/dist/backends/browser-use-adapter.js +219 -0
  25. package/dist/backends/browser-use-adapter.js.map +1 -0
  26. package/dist/backends/cdp-backend.d.ts +66 -0
  27. package/dist/backends/cdp-backend.d.ts.map +1 -0
  28. package/dist/backends/cdp-backend.js +273 -0
  29. package/dist/backends/cdp-backend.js.map +1 -0
  30. package/dist/backends/index.d.ts +80 -0
  31. package/dist/backends/index.d.ts.map +1 -0
  32. package/dist/backends/index.js +100 -0
  33. package/dist/backends/index.js.map +1 -0
  34. package/dist/backends/protocol.d.ts +156 -0
  35. package/dist/backends/protocol.d.ts.map +1 -0
  36. package/dist/backends/protocol.js +16 -0
  37. package/dist/backends/protocol.js.map +1 -0
  38. package/dist/backends/sentience-context.d.ts +136 -0
  39. package/dist/backends/sentience-context.d.ts.map +1 -0
  40. package/dist/backends/sentience-context.js +354 -0
  41. package/dist/backends/sentience-context.js.map +1 -0
  42. package/dist/backends/snapshot.d.ts +180 -0
  43. package/dist/backends/snapshot.d.ts.map +1 -0
  44. package/dist/backends/snapshot.js +308 -0
  45. package/dist/backends/snapshot.js.map +1 -0
  46. package/dist/canonicalization.d.ts +126 -0
  47. package/dist/canonicalization.d.ts.map +1 -0
  48. package/dist/canonicalization.js +161 -0
  49. package/dist/canonicalization.js.map +1 -0
  50. package/dist/index.d.ts +4 -0
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +42 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/ordinal.d.ts +90 -0
  55. package/dist/ordinal.d.ts.map +1 -0
  56. package/dist/ordinal.js +249 -0
  57. package/dist/ordinal.js.map +1 -0
  58. package/dist/snapshot-diff.d.ts +8 -15
  59. package/dist/snapshot-diff.d.ts.map +1 -1
  60. package/dist/snapshot-diff.js +38 -43
  61. package/dist/snapshot-diff.js.map +1 -1
  62. package/dist/snapshot.js +2 -0
  63. package/dist/snapshot.js.map +1 -1
  64. package/dist/tracing/indexer.d.ts.map +1 -1
  65. package/dist/tracing/indexer.js +3 -46
  66. package/dist/tracing/indexer.js.map +1 -1
  67. package/dist/tracing/types.d.ts +19 -0
  68. package/dist/tracing/types.d.ts.map +1 -1
  69. package/dist/types.d.ts +8 -0
  70. package/dist/types.d.ts.map +1 -1
  71. package/dist/verification.d.ts +177 -0
  72. package/dist/verification.d.ts.map +1 -0
  73. package/dist/verification.js +315 -0
  74. package/dist/verification.js.map +1 -0
  75. package/package.json +1 -1
  76. package/src/extension/injected_api.js +9 -2
  77. package/src/extension/manifest.json +1 -1
  78. package/src/extension/pkg/sentience_core_bg.wasm +0 -0
  79. package/src/extension/release.json +48 -47
package/README.md CHANGED
@@ -13,6 +13,7 @@ npx playwright install chromium
13
13
  ```
14
14
 
15
15
  **For local development:**
16
+
16
17
  ```bash
17
18
  npm install
18
19
  npm run build
@@ -44,7 +45,7 @@ const response = await agent.execute(
44
45
  console.log(response); // "I found the top result for wireless mouse on Amazon. It's priced at $24.99..."
45
46
 
46
47
  // Follow-up questions maintain context
47
- const followUp = await agent.chat("Add it to cart");
48
+ const followUp = await agent.chat('Add it to cart');
48
49
  console.log(followUp);
49
50
 
50
51
  await browser.close();
@@ -144,7 +145,9 @@ await browser.close();
144
145
  ## 🆕 What's New (2026-01-06)
145
146
 
146
147
  ### Human-like Typing
148
+
147
149
  Add realistic delays between keystrokes to mimic human typing:
150
+
148
151
  ```typescript
149
152
  // Type instantly (default)
150
153
  await typeText(browser, elementId, 'Hello World');
@@ -154,7 +157,9 @@ await typeText(browser, elementId, 'Hello World', false, 10);
154
157
  ```
155
158
 
156
159
  ### Scroll to Element
160
+
157
161
  Scroll elements into view with smooth animation:
162
+
158
163
  ```typescript
159
164
  const snap = await snapshot(browser);
160
165
  const button = find(snap, 'role=button text~"Submit"');
@@ -181,7 +186,7 @@ import {
181
186
  SentienceAgent,
182
187
  OpenAIProvider,
183
188
  Tracer,
184
- JsonlTraceSink
189
+ JsonlTraceSink,
185
190
  } from 'sentienceapi';
186
191
  import { randomUUID } from 'crypto';
187
192
 
@@ -235,6 +240,38 @@ Traces are **100% compatible** with Python SDK traces - use the same tools to an
235
240
 
236
241
  </details>
237
242
 
243
+ <details>
244
+ <summary><h2>🔍 Agent Runtime Verification</h2></summary>
245
+
246
+ `AgentRuntime` provides assertion predicates for runtime verification in agent loops, enabling programmatic verification of browser state during execution.
247
+
248
+ ```typescript
249
+ import { SentienceBrowser } from 'sentienceapi';
250
+ import { AgentRuntime, urlContains, exists, allOf } from 'sentienceapi';
251
+ import { createTracer } from 'sentienceapi';
252
+
253
+ const browser = new SentienceBrowser();
254
+ await browser.start();
255
+ const tracer = await createTracer({ runId: 'my-run', uploadTrace: false });
256
+ const runtime = new AgentRuntime(browser, browser.getPage(), tracer);
257
+
258
+ // Navigate and take snapshot
259
+ await browser.getPage().goto('https://example.com');
260
+ runtime.beginStep('Verify page');
261
+ await runtime.snapshot();
262
+
263
+ // Run assertions
264
+ runtime.assert(urlContains('example.com'), 'on_correct_domain');
265
+ runtime.assert(exists('role=heading'), 'has_heading');
266
+ runtime.assertDone(exists("text~'Example'"), 'task_complete');
267
+
268
+ console.log(`Task done: ${runtime.isTaskDone}`);
269
+ ```
270
+
271
+ **See example:** [examples/agent-runtime-verification.ts](examples/agent-runtime-verification.ts)
272
+
273
+ </details>
274
+
238
275
  ---
239
276
 
240
277
  <details>
@@ -261,14 +298,14 @@ async function main() {
261
298
  console.log(`Found ${snap.elements.length} elements`);
262
299
 
263
300
  // Find first product in viewport using spatial filtering
264
- const products = snap.elements
265
- .filter(el =>
301
+ const products = snap.elements.filter(
302
+ el =>
266
303
  el.role === 'link' &&
267
304
  el.visual_cues.is_clickable &&
268
305
  el.in_viewport &&
269
306
  !el.is_occluded &&
270
- el.bbox.y < 600 // First row
271
- );
307
+ el.bbox.y < 600 // First row
308
+ );
272
309
 
273
310
  if (products.length > 0) {
274
311
  // Sort by position (left to right, top to bottom)
@@ -323,12 +360,14 @@ main();
323
360
  **`snapshot(browser, options?)`** - Capture page state with AI-ranked elements
324
361
 
325
362
  Features:
363
+
326
364
  - Returns semantic elements with roles, text, importance scores, and bounding boxes
327
365
  - Optional screenshot capture (PNG/JPEG)
328
366
  - Optional visual overlay to see what elements are detected
329
367
  - TypeScript types for type safety
330
368
 
331
369
  **Example:**
370
+
332
371
  ```typescript
333
372
  const snap = await snapshot(browser, { screenshot: true, show_overlay: true });
334
373
 
@@ -353,6 +392,7 @@ for (const element of snap.elements) {
353
392
  - Powerful query DSL with multiple operators
354
393
 
355
394
  **Query Examples:**
395
+
356
396
  ```typescript
357
397
  // Find by role and text
358
398
  const button = find(snap, 'role=button text="Sign in"');
@@ -393,12 +433,13 @@ All actions return `ActionResult` with success status, timing, and outcome:
393
433
  const result = await click(browser, element.id);
394
434
 
395
435
  console.log(`Success: ${result.success}`);
396
- console.log(`Outcome: ${result.outcome}`); // "navigated", "dom_updated", "error"
436
+ console.log(`Outcome: ${result.outcome}`); // "navigated", "dom_updated", "error"
397
437
  console.log(`Duration: ${result.duration_ms}ms`);
398
438
  console.log(`URL changed: ${result.url_changed}`);
399
439
  ```
400
440
 
401
441
  **Coordinate-based clicking:**
442
+
402
443
  ```typescript
403
444
  import { clickRect } from './src';
404
445
 
@@ -416,7 +457,7 @@ if (element) {
416
457
  x: element.bbox.x,
417
458
  y: element.bbox.y,
418
459
  w: element.bbox.width,
419
- h: element.bbox.height
460
+ h: element.bbox.height,
420
461
  });
421
462
  }
422
463
  ```
@@ -430,6 +471,7 @@ if (element) {
430
471
  - **`expect(browser, selector)`** - Assertion helper with fluent API
431
472
 
432
473
  **Examples:**
474
+
433
475
  ```typescript
434
476
  // Wait for element (auto-detects optimal interval based on API usage)
435
477
  const result = await waitFor(browser, 'role=button text="Submit"', 10000);
@@ -447,9 +489,9 @@ const result = await waitFor(browser, 'role=button', 5000, undefined, true);
447
489
  const result = await waitFor(browser, 'role=button', 5000, 500, false);
448
490
 
449
491
  // Semantic wait conditions
450
- await waitFor(browser, 'clickable=true', 5000); // Wait for clickable element
451
- await waitFor(browser, 'importance>100', 5000); // Wait for important element
452
- await waitFor(browser, 'role=link visible=true', 5000); // Wait for visible link
492
+ await waitFor(browser, 'clickable=true', 5000); // Wait for clickable element
493
+ await waitFor(browser, 'importance>100', 5000); // Wait for important element
494
+ await waitFor(browser, 'role=link visible=true', 5000); // Wait for visible link
453
495
 
454
496
  // Assertions
455
497
  await expect(browser, 'role=button text="Submit"').toExist(5000);
@@ -475,7 +517,7 @@ import { showOverlay, clearOverlay } from 'sentienceapi';
475
517
  const snap = await snapshot(browser);
476
518
 
477
519
  // Show overlay anytime without re-snapshotting
478
- await showOverlay(browser, snap); // Auto-clears after 5 seconds
520
+ await showOverlay(browser, snap); // Auto-clears after 5 seconds
479
521
 
480
522
  // Highlight specific target element in red
481
523
  const button = find(snap, 'role=button text~"Submit"');
@@ -487,11 +529,13 @@ await clearOverlay(browser);
487
529
  ```
488
530
 
489
531
  **Color Coding:**
532
+
490
533
  - 🔴 Red: Target element
491
534
  - 🔵 Blue: Primary elements (`is_primary=true`)
492
535
  - 🟢 Green: Regular interactive elements
493
536
 
494
537
  **Visual Indicators:**
538
+
495
539
  - Border thickness/opacity scales with importance
496
540
  - Semi-transparent fill
497
541
  - Importance badges
@@ -504,21 +548,23 @@ await clearOverlay(browser);
504
548
  <summary><h3>📄 Content Reading</h3></summary>
505
549
 
506
550
  **`read(browser, options?)`** - Extract page content
551
+
507
552
  - `format: "text"` - Plain text extraction
508
553
  - `format: "markdown"` - High-quality markdown conversion (uses Turndown)
509
554
  - `format: "raw"` - Cleaned HTML (default)
510
555
 
511
556
  **Example:**
557
+
512
558
  ```typescript
513
559
  import { read } from './src';
514
560
 
515
561
  // Get markdown content
516
562
  const result = await read(browser, { format: 'markdown' });
517
- console.log(result.content); // Markdown text
563
+ console.log(result.content); // Markdown text
518
564
 
519
565
  // Get plain text
520
566
  const result = await read(browser, { format: 'text' });
521
- console.log(result.content); // Plain text
567
+ console.log(result.content); // Plain text
522
568
  ```
523
569
 
524
570
  </details>
@@ -527,11 +573,13 @@ console.log(result.content); // Plain text
527
573
  <summary><h3>📷 Screenshots</h3></summary>
528
574
 
529
575
  **`screenshot(browser, options?)`** - Standalone screenshot capture
576
+
530
577
  - Returns base64-encoded data URL
531
578
  - PNG or JPEG format
532
579
  - Quality control for JPEG (1-100)
533
580
 
534
581
  **Example:**
582
+
535
583
  ```typescript
536
584
  import { screenshot } from './src';
537
585
  import { writeFileSync } from 'fs';
@@ -558,6 +606,7 @@ const dataUrl = await screenshot(browser, { format: 'jpeg', quality: 85 });
558
606
  Find buttons, links, or any UI elements by their visible text without needing element IDs or CSS selectors. Returns exact pixel coordinates for each match.
559
607
 
560
608
  **Example:**
609
+
561
610
  ```typescript
562
611
  import { SentienceBrowser, findTextRect, clickRect } from 'sentienceapi';
563
612
 
@@ -565,8 +614,8 @@ const browser = await SentienceBrowser.create();
565
614
  await browser.getPage().goto('https://example.com');
566
615
 
567
616
  // Find "Sign In" button (simple string syntax)
568
- const result = await findTextRect(browser.getPage(), "Sign In");
569
- if (result.status === "success" && result.results) {
617
+ const result = await findTextRect(browser.getPage(), 'Sign In');
618
+ if (result.status === 'success' && result.results) {
570
619
  const firstMatch = result.results[0];
571
620
  console.log(`Found at: (${firstMatch.rect.x}, ${firstMatch.rect.y})`);
572
621
  console.log(`In viewport: ${firstMatch.in_viewport}`);
@@ -577,30 +626,31 @@ if (result.status === "success" && result.results) {
577
626
  x: firstMatch.rect.x,
578
627
  y: firstMatch.rect.y,
579
628
  w: firstMatch.rect.width,
580
- h: firstMatch.rect.height
629
+ h: firstMatch.rect.height,
581
630
  });
582
631
  }
583
632
  }
584
633
  ```
585
634
 
586
635
  **Advanced Options:**
636
+
587
637
  ```typescript
588
638
  // Case-sensitive search
589
639
  const result = await findTextRect(browser.getPage(), {
590
- text: "LOGIN",
591
- caseSensitive: true
640
+ text: 'LOGIN',
641
+ caseSensitive: true,
592
642
  });
593
643
 
594
644
  // Whole word only (won't match "login" as part of "loginButton")
595
645
  const result = await findTextRect(browser.getPage(), {
596
- text: "log",
597
- wholeWord: true
646
+ text: 'log',
647
+ wholeWord: true,
598
648
  });
599
649
 
600
650
  // Find multiple matches
601
651
  const result = await findTextRect(browser.getPage(), {
602
- text: "Buy",
603
- maxResults: 10
652
+ text: 'Buy',
653
+ maxResults: 10,
604
654
  });
605
655
  for (const match of result.results || []) {
606
656
  if (match.in_viewport) {
@@ -611,6 +661,7 @@ for (const match of result.results || []) {
611
661
  ```
612
662
 
613
663
  **Returns:** Promise<TextRectSearchResult> with:
664
+
614
665
  - **`status`**: "success" or "error"
615
666
  - **`results`**: Array of `TextMatch` objects with:
616
667
  - `text` - The matched text
@@ -620,6 +671,7 @@ for (const match of result.results || []) {
620
671
  - `in_viewport` - Whether visible in current viewport
621
672
 
622
673
  **Use Cases:**
674
+
623
675
  - Find buttons/links by visible text without CSS selectors
624
676
  - Get exact pixel coordinates for click automation
625
677
  - Verify text visibility and position on page
@@ -641,15 +693,15 @@ for (const match of result.results || []) {
641
693
  Elements returned by `snapshot()` have the following properties:
642
694
 
643
695
  ```typescript
644
- element.id // Unique identifier for interactions
645
- element.role // ARIA role (button, link, textbox, heading, etc.)
646
- element.text // Visible text content
647
- element.importance // AI importance score (0-1000)
648
- element.bbox // Bounding box (x, y, width, height)
649
- element.visual_cues // Visual analysis (is_primary, is_clickable, background_color)
650
- element.in_viewport // Is element visible in current viewport?
651
- element.is_occluded // Is element covered by other elements?
652
- element.z_index // CSS stacking order
696
+ element.id; // Unique identifier for interactions
697
+ element.role; // ARIA role (button, link, textbox, heading, etc.)
698
+ element.text; // Visible text content
699
+ element.importance; // AI importance score (0-1000)
700
+ element.bbox; // Bounding box (x, y, width, height)
701
+ element.visual_cues; // Visual analysis (is_primary, is_clickable, background_color)
702
+ element.in_viewport; // Is element visible in current viewport?
703
+ element.is_occluded; // Is element covered by other elements?
704
+ element.z_index; // CSS stacking order
653
705
  ```
654
706
 
655
707
  </details>
@@ -659,15 +711,15 @@ element.z_index // CSS stacking order
659
711
 
660
712
  ### Basic Operators
661
713
 
662
- | Operator | Description | Example |
663
- |----------|-------------|---------|
664
- | `=` | Exact match | `role=button` |
665
- | `!=` | Exclusion | `role!=link` |
666
- | `~` | Substring (case-insensitive) | `text~"sign in"` |
667
- | `^=` | Prefix match | `text^="Add"` |
668
- | `$=` | Suffix match | `text$="Cart"` |
669
- | `>`, `>=` | Greater than | `importance>500` |
670
- | `<`, `<=` | Less than | `bbox.y<600` |
714
+ | Operator | Description | Example |
715
+ | --------- | ---------------------------- | ---------------- |
716
+ | `=` | Exact match | `role=button` |
717
+ | `!=` | Exclusion | `role!=link` |
718
+ | `~` | Substring (case-insensitive) | `text~"sign in"` |
719
+ | `^=` | Prefix match | `text^="Add"` |
720
+ | `$=` | Suffix match | `text$="Cart"` |
721
+ | `>`, `>=` | Greater than | `importance>500` |
722
+ | `<`, `<=` | Less than | `bbox.y<600` |
671
723
 
672
724
  ### Supported Fields
673
725
 
@@ -712,7 +764,7 @@ const browser = new SentienceBrowser(undefined, undefined, false);
712
764
  const browser = new SentienceBrowser(undefined, undefined, true);
713
765
 
714
766
  // Auto-detect based on environment (default)
715
- const browser = new SentienceBrowser(); // headless=true if CI=true, else false
767
+ const browser = new SentienceBrowser(); // headless=true if CI=true, else false
716
768
  ```
717
769
 
718
770
  </details>
@@ -723,6 +775,7 @@ const browser = new SentienceBrowser(); // headless=true if CI=true, else false
723
775
  For users running from datacenters (AWS, DigitalOcean, etc.), you can configure a residential proxy to prevent IP-based detection by Cloudflare, Akamai, and other anti-bot services.
724
776
 
725
777
  **Supported Formats:**
778
+
726
779
  - HTTP: `http://username:password@host:port`
727
780
  - HTTPS: `https://username:password@host:port`
728
781
  - SOCKS5: `socks5://username:password@host:port`
@@ -787,9 +840,9 @@ await saveStorageState(browser.getContext(), 'auth.json');
787
840
  const browser2 = new SentienceBrowser(
788
841
  undefined, // apiKey
789
842
  undefined, // apiUrl
790
- false, // headless
791
- undefined, // proxy
792
- undefined, // userDataDir
843
+ false, // headless
844
+ undefined, // proxy
845
+ undefined, // userDataDir
793
846
  'auth.json' // storageState - inject saved session
794
847
  );
795
848
  await browser2.start();
@@ -797,12 +850,12 @@ await browser2.start();
797
850
 
798
851
  // Workflow 2: Persistent sessions (cookies persist across runs)
799
852
  const browser3 = new SentienceBrowser(
800
- undefined, // apiKey
801
- undefined, // apiUrl
802
- false, // headless
803
- undefined, // proxy
853
+ undefined, // apiKey
854
+ undefined, // apiUrl
855
+ false, // headless
856
+ undefined, // proxy
804
857
  './chrome_profile', // userDataDir - persist cookies
805
- undefined // storageState
858
+ undefined // storageState
806
859
  );
807
860
  await browser3.start();
808
861
  // First run: Log in
@@ -810,6 +863,7 @@ await browser3.start();
810
863
  ```
811
864
 
812
865
  **Benefits:**
866
+
813
867
  - Bypass login screens and CAPTCHAs with valid sessions
814
868
  - Save 5-10 agent steps and hundreds of tokens per run
815
869
  - Maintain stateful sessions for accessing authenticated pages
@@ -827,13 +881,15 @@ See `examples/auth-injection-agent.ts` for complete examples.
827
881
  <summary>Click to expand best practices</summary>
828
882
 
829
883
  ### 1. Wait for Dynamic Content
884
+
830
885
  ```typescript
831
886
  await browser.goto('https://example.com');
832
887
  await browser.getPage().waitForLoadState('networkidle');
833
- await new Promise(resolve => setTimeout(resolve, 1000)); // Extra buffer
888
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Extra buffer
834
889
  ```
835
890
 
836
891
  ### 2. Use Multiple Strategies for Finding Elements
892
+
837
893
  ```typescript
838
894
  // Try exact match first
839
895
  let btn = find(snap, 'role=button text="Add to Cart"');
@@ -845,6 +901,7 @@ if (!btn) {
845
901
  ```
846
902
 
847
903
  ### 3. Check Element Visibility Before Clicking
904
+
848
905
  ```typescript
849
906
  if (element.in_viewport && !element.is_occluded) {
850
907
  await click(browser, element.id);
@@ -852,6 +909,7 @@ if (element.in_viewport && !element.is_occluded) {
852
909
  ```
853
910
 
854
911
  ### 4. Handle Navigation
912
+
855
913
  ```typescript
856
914
  const result = await click(browser, linkId);
857
915
  if (result.url_changed) {
@@ -860,6 +918,7 @@ if (result.url_changed) {
860
918
  ```
861
919
 
862
920
  ### 5. Use Screenshots Sparingly
921
+
863
922
  ```typescript
864
923
  // Fast - no screenshot (only element data)
865
924
  const snap = await snapshot(browser);
@@ -869,6 +928,7 @@ const snap = await snapshot(browser, { screenshot: true });
869
928
  ```
870
929
 
871
930
  ### 6. Always Close Browser
931
+
872
932
  ```typescript
873
933
  const browser = new SentienceBrowser();
874
934
 
@@ -876,7 +936,7 @@ try {
876
936
  await browser.start();
877
937
  // ... your automation code
878
938
  } finally {
879
- await browser.close(); // Always clean up
939
+ await browser.close(); // Always clean up
880
940
  }
881
941
  ```
882
942
 
@@ -890,14 +950,18 @@ try {
890
950
  <summary>Click to expand common issues and solutions</summary>
891
951
 
892
952
  ### "Extension failed to load"
953
+
893
954
  **Solution:** Build the extension first:
955
+
894
956
  ```bash
895
957
  cd sentience-chrome
896
958
  ./build.sh
897
959
  ```
898
960
 
899
961
  ### "Cannot use import statement outside a module"
962
+
900
963
  **Solution:** Don't use `node` directly. Use `ts-node` or npm scripts:
964
+
901
965
  ```bash
902
966
  npx ts-node examples/hello.ts
903
967
  # or
@@ -905,13 +969,17 @@ npm run example:hello
905
969
  ```
906
970
 
907
971
  ### "Element not found"
972
+
908
973
  **Solutions:**
974
+
909
975
  - Ensure page is loaded: `await browser.getPage().waitForLoadState('networkidle')`
910
976
  - Use `waitFor()`: `await waitFor(browser, 'role=button', 10000)`
911
977
  - Debug elements: `console.log(snap.elements.map(el => el.text))`
912
978
 
913
979
  ### Button not clickable
980
+
914
981
  **Solutions:**
982
+
915
983
  - Check visibility: `element.in_viewport && !element.is_occluded`
916
984
  - Scroll to element: ``await browser.getPage().evaluate(`window.sentience_registry[${element.id}].scrollIntoView()`)``
917
985
 
@@ -948,6 +1016,7 @@ npm run example:hello
948
1016
  **⚠️ Important**: You cannot use `node` directly to run TypeScript files. Use one of these methods:
949
1017
 
950
1018
  ### Option 1: Using npm scripts (recommended)
1019
+
951
1020
  ```bash
952
1021
  npm run example:hello
953
1022
  npm run example:basic
@@ -956,6 +1025,7 @@ npm run example:wait
956
1025
  ```
957
1026
 
958
1027
  ### Option 2: Using ts-node directly
1028
+
959
1029
  ```bash
960
1030
  npx ts-node examples/hello.ts
961
1031
  # or if ts-node is installed globally:
@@ -963,6 +1033,7 @@ ts-node examples/hello.ts
963
1033
  ```
964
1034
 
965
1035
  ### Option 3: Compile then run
1036
+
966
1037
  ```bash
967
1038
  npm run build
968
1039
  # Then use compiled JavaScript from dist/
@@ -1001,7 +1072,7 @@ npm test -- snapshot.test.ts
1001
1072
 
1002
1073
  This project is licensed under either of:
1003
1074
 
1004
- * Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE-APACHE))
1005
- * MIT license ([LICENSE-MIT](./LICENSE-MIT))
1075
+ - Apache License, Version 2.0, ([LICENSE-APACHE](./LICENSE-APACHE))
1076
+ - MIT license ([LICENSE-MIT](./LICENSE-MIT))
1006
1077
 
1007
1078
  at your option.