agex 0.2.10 → 0.2.12

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.
@@ -178,6 +178,17 @@
178
178
  max-width: 80%;
179
179
  text-align: center;
180
180
  animation: ${EFFECTS_ID}-subtitle-slide-down 0.35s ease-out;
181
+ overflow: hidden;
182
+ }
183
+ .${EFFECTS_ID}-subtitle-progress {
184
+ position: absolute;
185
+ bottom: 0;
186
+ left: 0;
187
+ height: 2px;
188
+ background: color-mix(in srgb, var(--subtitle-fg, white) 15%, transparent);
189
+ border-radius: 0 0 8px 8px;
190
+ width: 0%;
191
+ transition: none;
181
192
  }
182
193
  .${EFFECTS_ID}-drawing-canvas {
183
194
  position: fixed;
@@ -547,39 +558,13 @@
547
558
  if (el) el.remove();
548
559
  },
549
560
 
550
- typeText(selector, text, charDelay) {
551
- charDelay = charDelay || 80;
552
- var el = utils.getElement(selector);
553
- if (!el) return 0;
554
- el.focus();
555
- var i = 0;
556
- var len = text.length;
557
- function typeNext() {
558
- if (i >= len) return;
559
- var ch = text[i];
560
- el.dispatchEvent(new KeyboardEvent('keydown', { key: ch, bubbles: true }));
561
- el.dispatchEvent(new KeyboardEvent('keypress', { key: ch, bubbles: true }));
562
- // For contenteditable elements, insert text differently
563
- if (el.isContentEditable) {
564
- document.execCommand('insertText', false, ch);
565
- } else {
566
- // Use InputEvent for proper React/framework compatibility
567
- var nativeInputValueSetter = Object.getOwnPropertyDescriptor(
568
- Object.getPrototypeOf(el), 'value'
569
- );
570
- if (nativeInputValueSetter && nativeInputValueSetter.set) {
571
- nativeInputValueSetter.set.call(el, el.value + ch);
572
- } else {
573
- el.value = el.value + ch;
574
- }
575
- el.dispatchEvent(new Event('input', { bubbles: true }));
576
- }
577
- el.dispatchEvent(new KeyboardEvent('keyup', { key: ch, bubbles: true }));
578
- i++;
579
- if (i < len) setTimeout(typeNext, charDelay);
580
- }
581
- typeNext();
582
- return len * charDelay;
561
+ setPosition(x, y) {
562
+ var c = document.getElementById('agex-cursor');
563
+ if (!c) return;
564
+ c.style.transition = 'none';
565
+ c.style.left = x + 'px';
566
+ c.style.top = y + 'px';
567
+ this._lastPos = { x: x, y: y };
583
568
  },
584
569
 
585
570
  fadeOut() {
@@ -1429,10 +1414,29 @@
1429
1414
  if (fg) subtitle.style.setProperty('--subtitle-fg', fg);
1430
1415
  if (bg) subtitle.style.setProperty('--subtitle-bg', bg);
1431
1416
  subtitle.textContent = text;
1417
+
1418
+ var bar = document.createElement('div');
1419
+ bar.className = `${EFFECTS_ID}-subtitle-progress`;
1420
+ subtitle.appendChild(bar);
1421
+
1422
+ var startTime = performance.now();
1423
+ var barDuration = duration > 0 ? duration : 30000;
1424
+ var rafId = 0;
1425
+ function tick() {
1426
+ var elapsed = performance.now() - startTime;
1427
+ var pct = Math.min(elapsed / barDuration * 100, 100);
1428
+ bar.style.width = pct + '%';
1429
+ if (pct < 100) rafId = requestAnimationFrame(tick);
1430
+ }
1431
+ rafId = requestAnimationFrame(tick);
1432
+
1432
1433
  document.body.appendChild(subtitle);
1433
1434
 
1434
1435
  if (duration > 0) {
1435
- setTimeout(() => subtitle.remove(), duration);
1436
+ setTimeout(function() {
1437
+ cancelAnimationFrame(rafId);
1438
+ subtitle.remove();
1439
+ }, duration);
1436
1440
  }
1437
1441
  },
1438
1442
 
@@ -1636,11 +1640,23 @@
1636
1640
  scrollElementToCenter(selector) {
1637
1641
  var el = typeof selector === 'string' ? document.querySelector(selector) : selector;
1638
1642
  if (!el) return false;
1639
- // scrollIntoView with block:'center' handles nested scrollable containers
1640
1643
  el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'instant' });
1641
1644
  return true;
1642
1645
  },
1643
1646
 
1647
+ scrollElementToCenterSmooth(selector) {
1648
+ var el = typeof selector === 'string' ? document.querySelector(selector) : selector;
1649
+ if (!el) return 0;
1650
+ var rect = el.getBoundingClientRect();
1651
+ var viewH = window.innerHeight;
1652
+ var centerY = rect.top + rect.height / 2;
1653
+ if (centerY > viewH * 0.2 && centerY < viewH * 0.8) return 0;
1654
+ var dist = Math.abs(centerY - viewH / 2);
1655
+ var duration = Math.max(600, Math.min(2000, Math.round(dist * 1.5)));
1656
+ el.scrollIntoView({ block: 'center', inline: 'nearest', behavior: 'smooth' });
1657
+ return duration;
1658
+ },
1659
+
1644
1660
  scrollToCoords(y, viewportHeight, elHeight) {
1645
1661
  window.scrollTo({
1646
1662
  top: window.scrollY + y - (viewportHeight / 2) + (elHeight / 2),
@@ -1685,6 +1701,31 @@
1685
1701
  }
1686
1702
  };
1687
1703
 
1704
+ // Enable or disable page CSS animations & transitions (preserves agex effects)
1705
+ function setPageAnimations(enabled) {
1706
+ var id = EFFECTS_ID + '-disable-animations';
1707
+ var existing = document.getElementById(id);
1708
+ if (enabled) {
1709
+ if (existing) existing.remove();
1710
+ return;
1711
+ }
1712
+ if (existing) return;
1713
+ var style = document.createElement('style');
1714
+ style.id = id;
1715
+ style.textContent = `
1716
+ *:not(.${EFFECTS_ID}):not(.${EFFECTS_ID} *) {
1717
+ animation: none !important;
1718
+ animation-delay: 0s !important;
1719
+ animation-duration: 0s !important;
1720
+ transition: none !important;
1721
+ transition-delay: 0s !important;
1722
+ transition-duration: 0s !important;
1723
+ scroll-behavior: auto !important;
1724
+ }
1725
+ `;
1726
+ document.head.appendChild(style);
1727
+ }
1728
+
1688
1729
  // Clear all effects
1689
1730
  function clearAll() {
1690
1731
  effects.highlight.clear();
@@ -1720,6 +1761,7 @@
1720
1761
  window.__agexEffects = {
1721
1762
  apply,
1722
1763
  clearAll,
1764
+ setPageAnimations,
1723
1765
  banner,
1724
1766
  proof,
1725
1767
  ...effects,
@@ -11,14 +11,38 @@ if [ -z "$SELECTOR" ]; then
11
11
  exit 1
12
12
  fi
13
13
 
14
- # Scroll element into center of its container before measuring position
14
+ # Smooth-scroll element into center of viewport so the viewer can follow
15
15
  if [[ "$SELECTOR" == @* ]]; then
16
- agent-browser scrollintoview "$SELECTOR" {{SESSION_ARG}} >/dev/null 2>&1
16
+ # For @ref: get bounding box first, then smooth-scroll by coordinates
17
+ PRE_STYLES=$(agent-browser get styles "$SELECTOR" --json {{SESSION_ARG}} 2>&1) || true
18
+ PRE_Y=$(echo "$PRE_STYLES" | grep -o '"y":[0-9.-]*' | head -1 | cut -d: -f2)
19
+ PRE_H=$(echo "$PRE_STYLES" | grep -o '"height":[0-9.-]*' | head -1 | cut -d: -f2)
20
+ if [ -n "$PRE_Y" ] && [ -n "$PRE_H" ]; then
21
+ SCROLL_DUR=$(agent-browser eval "(function(){ var viewH=window.innerHeight; var centerY=${PRE_Y}+${PRE_H}/2; if(centerY>viewH*0.2 && centerY<viewH*0.8) return '0'; var dist=Math.abs(centerY-viewH/2); var dur=Math.max(600,Math.min(2000,Math.round(dist*1.5))); window.scrollBy({top:centerY-viewH/2,behavior:'smooth'}); return ''+dur; })()" {{SESSION_ARG}} 2>/dev/null || echo "0")
22
+ SCROLL_DUR=$(echo "$SCROLL_DUR" | tr -d '[:space:]"')
23
+ if [ -n "$SCROLL_DUR" ] && [ "$SCROLL_DUR" != "0" ]; then
24
+ SCROLL_WAIT=$((SCROLL_DUR + 200))
25
+ agent-browser wait "$SCROLL_WAIT" {{SESSION_ARG}} >/dev/null 2>&1
26
+ else
27
+ agent-browser wait 300 {{SESSION_ARG}} >/dev/null 2>&1
28
+ fi
29
+ else
30
+ # Fallback: use instant scrollintoview
31
+ agent-browser scrollintoview "$SELECTOR" {{SESSION_ARG}} >/dev/null 2>&1
32
+ agent-browser wait 300 {{SESSION_ARG}} >/dev/null 2>&1
33
+ fi
17
34
  else
18
35
  ESCAPED_SELECTOR=$(printf '%s' "$SELECTOR" | sed "s/'/\\\\'/g")
19
- agent-browser eval "window.__agexEffects.proof.scrollElementToCenter('${ESCAPED_SELECTOR}')" {{SESSION_ARG}} >/dev/null 2>&1
36
+ SCROLL_DUR=$(agent-browser eval "'' + (window.__agexEffects ? window.__agexEffects.proof.scrollElementToCenterSmooth('${ESCAPED_SELECTOR}') : 0)" {{SESSION_ARG}} 2>/dev/null || echo "0")
37
+ SCROLL_DUR=$(echo "$SCROLL_DUR" | tr -d '[:space:]"')
38
+ if [ -z "$SCROLL_DUR" ] || [ "$SCROLL_DUR" = "0" ]; then
39
+ agent-browser eval "window.__agexEffects.proof.scrollElementToCenter('${ESCAPED_SELECTOR}')" {{SESSION_ARG}} >/dev/null 2>&1
40
+ agent-browser wait 300 {{SESSION_ARG}} >/dev/null 2>&1
41
+ else
42
+ SCROLL_WAIT=$((SCROLL_DUR + 200))
43
+ agent-browser wait "$SCROLL_WAIT" {{SESSION_ARG}} >/dev/null 2>&1
44
+ fi
20
45
  fi
21
- agent-browser wait 300 {{SESSION_ARG}} >/dev/null 2>&1
22
46
 
23
47
  # Get element bounding box without interacting with it
24
48
  if [[ "$SELECTOR" == @* ]]; then
@@ -69,11 +93,39 @@ WAIT_MS=$((ANIM_DURATION + 300))
69
93
  agent-browser wait "$WAIT_MS" {{SESSION_ARG}} >/dev/null 2>&1
70
94
  agent-browser wait 1000 {{SESSION_ARG}} >/dev/null 2>&1
71
95
 
96
+ # Re-measure element position right before clicking (it may have moved during animation)
97
+ if [[ "$SELECTOR" == @* ]]; then
98
+ STYLES2=$(agent-browser get styles "$SELECTOR" --json {{SESSION_ARG}} 2>&1) || true
99
+ EL_X2=$(echo "$STYLES2" | grep -o '"x":[0-9.-]*' | head -1 | cut -d: -f2)
100
+ EL_Y2=$(echo "$STYLES2" | grep -o '"y":[0-9.-]*' | head -1 | cut -d: -f2)
101
+ EL_W2=$(echo "$STYLES2" | grep -o '"width":[0-9.-]*' | head -1 | cut -d: -f2)
102
+ EL_H2=$(echo "$STYLES2" | grep -o '"height":[0-9.-]*' | head -1 | cut -d: -f2)
103
+ if [ -n "$EL_X2" ] && [ -n "$EL_Y2" ] && [ -n "$EL_W2" ] && [ -n "$EL_H2" ]; then
104
+ CLICK_X=$(echo "$EL_X2 + $EL_W2 / 2" | bc -l)
105
+ CLICK_Y=$(echo "$EL_Y2 + $EL_H2 / 2" | bc -l)
106
+ fi
107
+ else
108
+ BOX2=$(agent-browser eval "JSON.stringify(window.__agexEffects.proof.getBoundingBox('${ESCAPED_SELECTOR}'))" {{SESSION_ARG}} 2>&1) || true
109
+ if [ -n "$BOX2" ] && [[ "$BOX2" != "null" ]] && [[ "$BOX2" != *"error"* ]]; then
110
+ EL_X2=$(echo "$BOX2" | grep -o '"x":[0-9.-]*' | cut -d: -f2)
111
+ EL_Y2=$(echo "$BOX2" | grep -o '"y":[0-9.-]*' | cut -d: -f2)
112
+ EL_W2=$(echo "$BOX2" | grep -o '"width":[0-9.-]*' | cut -d: -f2)
113
+ EL_H2=$(echo "$BOX2" | grep -o '"height":[0-9.-]*' | cut -d: -f2)
114
+ if [ -n "$EL_X2" ] && [ -n "$EL_Y2" ] && [ -n "$EL_W2" ] && [ -n "$EL_H2" ]; then
115
+ CLICK_X=$(echo "$EL_X2 + $EL_W2 / 2" | bc -l)
116
+ CLICK_Y=$(echo "$EL_Y2 + $EL_H2 / 2" | bc -l)
117
+ fi
118
+ fi
119
+ fi
120
+
121
+ # Snap cursor to fresh position so ripple lands on the actual element
122
+ agent-browser eval "window.__agexEffects.cursor.setPosition(${CLICK_X}, ${CLICK_Y})" {{SESSION_ARG}} >/dev/null 2>&1
123
+
72
124
  # Show click ripple and perform the actual click
73
125
  agent-browser eval "window.__agexEffects.cursor.showClick(${CLICK_X}, ${CLICK_Y})" {{SESSION_ARG}} >/dev/null 2>&1
74
126
  agent-browser click "$SELECTOR" {{SESSION_ARG}} >/dev/null 2>&1
75
127
 
76
- # Sync _lastPos to the actual native click position (element center)
128
+ # Sync _lastPos to the actual click position
77
129
  # so the next animateToPosition starts from where the native mouse really is
78
130
  agent-browser eval "window.__agexEffects.cursor._lastPos = { x: ${CLICK_X}, y: ${CLICK_Y} }" {{SESSION_ARG}} >/dev/null 2>&1
79
131
 
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ # Enable or disable CSS animations and transitions on the page.
3
+ # Preserves agex visual effects.
4
+ # Usage: ab-toggle-animations true|false
5
+ # true = enable animations (default browser behavior)
6
+ # false = disable animations
7
+ ENABLED="${1:-true}"
8
+ {{FX_INJECT_HELPER}}
9
+ if [ "$ENABLED" = "false" ]; then
10
+ agent-browser eval "window.__agexEffects.setPageAnimations(false)" {{SESSION_ARG}} >/dev/null 2>&1
11
+ echo "page animations disabled"
12
+ else
13
+ agent-browser eval "window.__agexEffects.setPageAnimations(true)" {{SESSION_ARG}} >/dev/null 2>&1
14
+ echo "page animations enabled"
15
+ fi
@@ -1,7 +1,6 @@
1
1
  #!/bin/bash
2
- # Smooth type: moves cursor to input, clicks to focus, then types text in-browser
2
+ # Smooth type: moves cursor to input, clicks to focus, then types text slowly
3
3
  # Uses ab-click for the animated cursor movement + click
4
- # Typing happens entirely in JS (one eval call) instead of per-character shell commands
5
4
  # Usage: ab-type <selector|@ref> "text"
6
5
  SELECTOR="$1"
7
6
  TEXT="$2"
@@ -13,35 +12,28 @@ fi
13
12
  # Move cursor to input and click to focus (animated)
14
13
  ab-click "$SELECTOR"
15
14
 
15
+ # Show glow focus effect on the input
16
16
  ESCAPED_SEL=$(printf '%s' "$SELECTOR" | sed "s/'/\\\\'/g")
17
- ESCAPED_TEXT=$(printf '%s' "$TEXT" | sed "s/'/\\\\'/g")
18
-
19
- # Show glow focus effect, lock cursor, type text all in one eval
20
- # typeText returns total duration in ms; we wait for it in shell
21
- TYPE_DURATION=$(agent-browser eval "(function(){
22
- var fx = window.__agexEffects;
23
- if (!fx) return '0';
24
- fx.cursor.showInputFocus('${ESCAPED_SEL}');
25
- if (window.__agexCursor) window.__agexCursor.setAnimationLock(true);
26
- var dur = fx.cursor.typeText('${ESCAPED_SEL}', '${ESCAPED_TEXT}', 80);
27
- return '' + dur;
28
- })()" {{SESSION_ARG}} 2>/dev/null)
29
-
30
- TYPE_DURATION=$(echo "$TYPE_DURATION" | tr -d '[:space:]"')
31
- if [ -z "$TYPE_DURATION" ] || [ "$TYPE_DURATION" = "0" ]; then
32
- TYPE_DURATION=1000
33
- fi
17
+ agent-browser eval "window.__agexEffects.cursor.showInputFocus('${ESCAPED_SEL}')" {{SESSION_ARG}} >/dev/null 2>&1
18
+
19
+ # Lock demo cursor so native mouse moves during typing don't cause jumps
20
+ agent-browser eval "if(window.__agexCursor) window.__agexCursor.setAnimationLock(true)" {{SESSION_ARG}} >/dev/null 2>&1
21
+
22
+ # Type text one character at a time with a human-like delay
23
+ LENGTH=${#TEXT}
24
+ for (( i=0; i<LENGTH; i++ )); do
25
+ CHAR="${TEXT:$i:1}"
26
+ agent-browser type "$SELECTOR" "$CHAR" {{SESSION_ARG}} >/dev/null 2>&1
27
+ agent-browser wait 70 {{SESSION_ARG}} >/dev/null 2>&1
28
+ done
29
+
30
+ # Brief pause so viewer can read the typed text
31
+ agent-browser wait 400 {{SESSION_ARG}} >/dev/null 2>&1
32
+
33
+ # Clear glow focus effect
34
+ agent-browser eval "window.__agexEffects.cursor.clearInputFocus()" {{SESSION_ARG}} >/dev/null 2>&1
34
35
 
35
- # Wait for typing animation to finish + brief pause for viewer to read
36
- WAIT_MS=$((TYPE_DURATION + 400))
37
- agent-browser wait "$WAIT_MS" {{SESSION_ARG}} >/dev/null 2>&1
38
-
39
- # Clear glow focus effect and unlock cursor
40
- agent-browser eval "(function(){
41
- var fx = window.__agexEffects;
42
- if (!fx) return;
43
- fx.cursor.clearInputFocus();
44
- if (window.__agexCursor) window.__agexCursor.setAnimationLock(false);
45
- })()" {{SESSION_ARG}} >/dev/null 2>&1
36
+ # Unlock demo cursor
37
+ agent-browser eval "if(window.__agexCursor) window.__agexCursor.setAnimationLock(false)" {{SESSION_ARG}} >/dev/null 2>&1
46
38
 
47
39
  echo "typed \"$TEXT\" into $SELECTOR"
@@ -5475,6 +5475,7 @@ function getScriptEntries(videoEnabled) {
5475
5475
  { outputName: "ab-move", scriptFile: "ab-move.sh" },
5476
5476
  { outputName: "ab-click", scriptFile: "ab-click.sh" },
5477
5477
  { outputName: "ab-type", scriptFile: "ab-type.sh" },
5478
+ { outputName: "ab-toggle-animations", scriptFile: "ab-toggle-animations.sh" },
5478
5479
  { outputName: "agent-browser", scriptFile: "agent-browser-wrapper.sh" }
5479
5480
  ];
5480
5481
  }
@@ -5485,36 +5486,54 @@ function loadAndRenderScript(scriptFile, vars) {
5485
5486
 
5486
5487
  // ../browse/dist/workspace.js
5487
5488
  var log8 = createLogger("browse");
5488
- function resolveAgentBrowser() {
5489
+ function findAgentBrowser() {
5490
+ let binPath;
5489
5491
  try {
5490
- const binPath = execSync2("which agent-browser", { encoding: "utf-8" }).trim();
5491
- log8.debug(`resolved agent-browser: ${binPath}`);
5492
- let home;
5493
- const binDir = path4.dirname(binPath);
5494
- const npmGlobalCandidate = path4.join(binDir, "..", "lib", "node_modules", "agent-browser");
5495
- if (fs3.existsSync(path4.join(npmGlobalCandidate, "package.json"))) {
5496
- home = path4.resolve(npmGlobalCandidate);
5497
- }
5498
- if (!home) {
5499
- try {
5500
- const realBin = fs3.realpathSync(binPath);
5501
- let dir = path4.dirname(realBin);
5502
- for (let i = 0; i < 5; i++) {
5503
- if (fs3.existsSync(path4.join(dir, "package.json"))) {
5504
- home = dir;
5505
- break;
5506
- }
5507
- dir = path4.dirname(dir);
5492
+ binPath = execSync2("which agent-browser", { encoding: "utf-8" }).trim();
5493
+ } catch {
5494
+ return void 0;
5495
+ }
5496
+ log8.debug(`resolved agent-browser: ${binPath}`);
5497
+ let home;
5498
+ const binDir = path4.dirname(binPath);
5499
+ const npmGlobalCandidate = path4.join(binDir, "..", "lib", "node_modules", "agent-browser");
5500
+ if (fs3.existsSync(path4.join(npmGlobalCandidate, "package.json"))) {
5501
+ home = path4.resolve(npmGlobalCandidate);
5502
+ }
5503
+ if (!home) {
5504
+ try {
5505
+ const realBin = fs3.realpathSync(binPath);
5506
+ let dir = path4.dirname(realBin);
5507
+ for (let i = 0; i < 5; i++) {
5508
+ if (fs3.existsSync(path4.join(dir, "package.json"))) {
5509
+ home = dir;
5510
+ break;
5508
5511
  }
5509
- } catch {
5512
+ dir = path4.dirname(dir);
5510
5513
  }
5514
+ } catch {
5511
5515
  }
5512
- log8.debug(`agent-browser home: ${home ?? "not found"}`);
5513
- return { bin: binPath, home };
5514
- } catch {
5515
- log8.warn("agent-browser not found in PATH, using bare command name");
5516
- return { bin: "agent-browser" };
5517
5516
  }
5517
+ log8.debug(`agent-browser home: ${home ?? "not found"}`);
5518
+ return { bin: binPath, home };
5519
+ }
5520
+ function resolveAgentBrowser() {
5521
+ const found = findAgentBrowser();
5522
+ if (found)
5523
+ return found;
5524
+ log8.info("agent-browser not found in PATH, installing globally...");
5525
+ try {
5526
+ execSync2("npm install -g agent-browser", { encoding: "utf-8", stdio: "pipe" });
5527
+ log8.info("agent-browser installed successfully");
5528
+ } catch (err) {
5529
+ const detail = (err?.stderr ?? err?.stdout)?.toString().trim() || err?.message || "";
5530
+ throw new BrowserError(`Failed to install agent-browser globally: ${detail}`);
5531
+ }
5532
+ const installed = findAgentBrowser();
5533
+ if (!installed) {
5534
+ throw new BrowserError("agent-browser not found in PATH after global install");
5535
+ }
5536
+ return installed;
5518
5537
  }
5519
5538
  function buildFxInjectHelper(sessionArg, initScriptPath) {
5520
5539
  return `
@@ -5792,6 +5811,15 @@ TYPING INTO INPUTS:
5792
5811
  ALWAYS use ab-type or agent-browser fill to type into inputs.
5793
5812
  NEVER set .value via eval \u2014 it does NOT trigger React/framework events and buttons stay disabled.
5794
5813
  ab-type @e1 "text" # Best: animated cursor + slow typing (triggers all events)
5814
+ agent-browser fill @e1 "text" # Instant replace (clears existing text)
5815
+
5816
+ IMPORTANT: ab-type APPENDS text \u2014 it does NOT clear existing content.
5817
+ If the input already has text and you want to REPLACE it, clear first:
5818
+ agent-browser fill @e1 "text" # Easiest: instant replace
5819
+ # OR for animated typing with clear:
5820
+ ab-click @e1 # Focus the input
5821
+ agent-browser key @e1 Meta+a # Select all existing text
5822
+ ab-type @e1 "new text" # First char replaces selection, rest appends
5795
5823
 
5796
5824
  BROWSER:
5797
5825
  agent-browser snapshot # Get ALL elements with refs
package/dist/cli.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  timestamp,
24
24
  validate,
25
25
  viewportStringSchema
26
- } from "./chunk-HPJHT4WX.js";
26
+ } from "./chunk-IKAOVJCU.js";
27
27
 
28
28
  // src/cli.ts
29
29
  import { defineCommand as defineCommand7, runMain } from "citty";
@@ -165,11 +165,8 @@ DEMO RULES are behind-the-scenes instructions. They must NOT appear in subtitles
165
165
  WORKFLOW:
166
166
  1. PLAN: Understand the task
167
167
  2. OPEN: ab-open "<url>" FIRST (required before any other command)
168
- 3. FREEZE ANIMATIONS: Immediately after opening, stop all CSS animations/transitions:
169
- agent-browser eval "var s=document.createElement('style');s.id='__agex-freeze';s.textContent='*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}';document.head.appendChild(s)"
170
- This prevents tickers, marquees, and other animations from producing duplicate frames in the recording.
171
- 4. EXECUTE: Interact, take screenshots
172
- 5. RECORD: ab-record-start, perform actions, ab-close
168
+ 3. EXECUTE: Interact, take screenshots
169
+ 4. RECORD: ab-record-start, perform actions, ab-close
173
170
 
174
171
  STRATEGY:
175
172
  - Open the URL and explore the page
@@ -180,7 +177,8 @@ COMMANDS:
180
177
  ab-open "<url>" # Open URL (ALWAYS quote!)
181
178
  ab-record-start # Start recording
182
179
  ab-close [1 2 ...] # Stop recording and merge segments
183
- ab-screenshot <name>.png # Capture screenshot
180
+ ab-screenshot <NNN-name>.png # Capture screenshot (e.g. 001-homepage.png, 002-menu.png)
181
+ ab-toggle-animations true|false # (optional) Enable/disable CSS animations. WARNING: disabling may hide elements that rely on CSS transitions to render.
184
182
 
185
183
  EFFECTS (optional \u2014 use only if the task asks for subtitles, highlights, etc.):
186
184
  fx-subtitle "text" # Show subtitle at bottom (persistent)
@@ -205,8 +203,16 @@ BROWSER:
205
203
  agent-browser scrollintoview @e1 # Smooth scroll to element
206
204
  agent-browser wait <ms> # Wait milliseconds
207
205
  ab-click @e1 # Click element (smooth cursor animation)
208
- ab-type @e1 "text" # Click input + type text slowly
209
- agent-browser fill @e2 "text" # Fill input (instant)
206
+ ab-type @e1 "text" # Click input + type text slowly (APPENDS to existing text)
207
+ agent-browser fill @e2 "text" # Fill input (instant, replaces existing text)
208
+
209
+ CLEARING INPUTS BEFORE TYPING:
210
+ ab-type APPENDS text \u2014 it does NOT clear existing content.
211
+ If the input already has text and you want to REPLACE it, clear it first:
212
+ agent-browser eval "var el=document.querySelector('[data-ref]'); el.select && el.select()" # select all text
213
+ agent-browser key @e1 Backspace # delete selected text
214
+ ab-type @e1 "new text" # now type fresh
215
+ Or simply use: agent-browser fill @e1 "text" # instant replace (no animation)
210
216
  agent-browser eval '<js>' # Run JavaScript
211
217
 
212
218
  SNAPSHOT TIPS:
@@ -225,10 +231,9 @@ RULES:
225
231
  - snapshot -i = interactive only (buttons, links, inputs)
226
232
  - snapshot (no flags) = ALL elements including images, text, logos
227
233
  - Use ab-record-start BEFORE the actions you want to capture
228
- - Use ab-screenshot at key moments for still evidence
234
+ - Use ab-screenshot with numbered names (001-xxx.png, 002-xxx.png) at key moments for sequential evidence
229
235
  - ALWAYS end with ab-close to finalize the recording
230
- - If you made ANY DOM changes via agent-browser eval BEFORE ab-record-start (e.g. freezing animations, hiding elements, injecting styles), you MUST re-apply them AFTER ab-record-start. DOM state does not persist across recording start. In particular, always re-inject the animation freeze style after ab-record-start:
231
- agent-browser eval "if(!document.getElementById('__agex-freeze')){var s=document.createElement('style');s.id='__agex-freeze';s.textContent='*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}';document.head.appendChild(s)}"
236
+ - If you made ANY DOM changes via agent-browser eval BEFORE ab-record-start (e.g. hiding elements, injecting styles), you MUST re-apply them AFTER ab-record-start. DOM state does not persist across recording start.
232
237
 
233
238
  FINISHING:
234
239
  After completing the task, run ab-close to stop recording.
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  provePr,
6
6
  runAgent,
7
7
  runReview
8
- } from "./chunk-HPJHT4WX.js";
8
+ } from "./chunk-IKAOVJCU.js";
9
9
  export {
10
10
  AgexError,
11
11
  isAgexError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agex",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,12 +25,12 @@
25
25
  "tsup": "^8.4.0",
26
26
  "typescript": "^5.9.3",
27
27
  "vitest": "^2.1.9",
28
- "agex-agent": "0.1.0",
29
28
  "agex-browse": "0.1.0",
30
29
  "agex-core": "0.1.0",
31
- "agex-demo": "0.1.0",
30
+ "agex-agent": "0.1.0",
32
31
  "agex-prove": "0.1.0",
33
32
  "agex-prove-pr": "0.1.0",
33
+ "agex-demo": "0.1.0",
34
34
  "agex-review": "0.1.0"
35
35
  },
36
36
  "scripts": {