leapfrog-mcp 0.7.0 → 0.7.2

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.
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import { adaptiveNavigate, formatAdaptiveResult } from "./adaptive-wait.js";
27
27
  import { runStealthAudit } from "./stealth-audit.js";
28
28
  import { exportSession, replayRecording } from "./recording.js";
29
29
  import { paginate } from "./paginate.js";
30
- import { getHUDInitScript, getHUDUpdateScript, getClickRippleScript } from "./session-hud.js";
30
+ import { getHUDInitScript, getHUDUpdateScript, getClickRippleScript, getAgentEyesInitScript } from "./session-hud.js";
31
31
  import { getDetectionInitScript, getDetectionCheckScript, getResolutionCheckScript, parseDetectionResult, getPressAndHoldDetectScript, solvePressAndHold } from "./intervention.js";
32
32
  import { getConsentDismissScript, getCacheSelectorScript, getTermsAutoCheckScript } from "./consent-dismiss.js";
33
33
  import { solveCaptcha, isCaptchaSolverEnabled } from "./captcha-solver.js";
@@ -129,9 +129,9 @@ if (LEAP_TILE && LEAP_TILE !== "false") {
129
129
  const defaultW = LEAP_SCREEN_WIDTH > 0 ? LEAP_SCREEN_WIDTH : detectedScreen?.width ?? 1920;
130
130
  const defaultH = LEAP_SCREEN_HEIGHT > 0 ? LEAP_SCREEN_HEIGHT : detectedScreen?.height ?? 1080;
131
131
  tilesCoord = new TilesCoordinator(defaultW, defaultH);
132
- // Purge ALL slots not owned by this process handles zombie PIDs
133
- // from /mcp reconnects where old node process lingers alive.
134
- tilesCoord.purgeOtherPids().catch(() => { });
132
+ // Reap dead PIDs on startup clean up crashed/killed instances.
133
+ // Do NOT purge other live PIDs they're other terminals we want to tile with.
134
+ tilesCoord.reapDeadSlots().catch(() => { });
135
135
  // File watcher only needed for multi-terminal mode (multiple Leapfrog instances).
136
136
  // In single-instance mode, the watcher causes spurious reflows that fight
137
137
  // with external monitor positioning. Only enable when explicitly requested.
@@ -369,6 +369,8 @@ server.registerTool("session_create", {
369
369
  }
370
370
  // Always inject intervention detection (lightweight MutationObserver)
371
371
  await session.context.addInitScript(getDetectionInitScript());
372
+ // Agent eyes — cursor dot + scroll indicator (zero Node overhead, listens to native DOM events)
373
+ await session.context.addInitScript(getAgentEyesInitScript());
372
374
  attachAdBlocker(session.context);
373
375
  // Start tracing if enabled
374
376
  if (LEAP_TRACE) {
@@ -427,6 +429,7 @@ server.registerTool("session_create_batch", {
427
429
  if (LEAP_AUTO_CONSENT)
428
430
  await session.context.addInitScript(getConsentDismissScript());
429
431
  await session.context.addInitScript(getDetectionInitScript());
432
+ await session.context.addInitScript(getAgentEyesInitScript());
430
433
  attachAdBlocker(session.context);
431
434
  if (LEAP_TRACE)
432
435
  await session.context.tracing.start({ screenshots: true, snapshots: true });
@@ -16,5 +16,11 @@ export declare function getClickRippleScript(x: number, y: number): string;
16
16
  */
17
17
  export declare function getScrollToTargetZoomIn(selector: string): string;
18
18
  export declare function getScrollToTargetZoomOut(selector: string): string;
19
+ /**
20
+ * Returns JS to inject cursor tracking + scroll indicator for headed sessions.
21
+ * Always-on for headed mode — not gated by LEAP_HUD.
22
+ * Zero Node.js overhead: listens to native DOM events dispatched by Playwright.
23
+ */
24
+ export declare function getAgentEyesInitScript(): string;
19
25
  /** Legacy single-call version (sync scroll only, no zoom). */
20
26
  export declare function getScrollToTargetScript(selector: string): string;
@@ -79,6 +79,7 @@ export function getHUDInitScript(sessionName) {
79
79
  container.appendChild(ripple);
80
80
  ripple.addEventListener('animationend', function() { ripple.remove(); });
81
81
  };
82
+
82
83
  })();`;
83
84
  }
84
85
  // ─── Live Update Scripts ───────────────────────────────────────────────────
@@ -124,6 +125,115 @@ export function getScrollToTargetZoomOut(selector) {
124
125
  }
125
126
  })()`;
126
127
  }
128
+ // ─── Agent Eyes Init Script ───────────────────────────────────────────────
129
+ /**
130
+ * Returns JS to inject cursor tracking + scroll indicator for headed sessions.
131
+ * Always-on for headed mode — not gated by LEAP_HUD.
132
+ * Zero Node.js overhead: listens to native DOM events dispatched by Playwright.
133
+ */
134
+ export function getAgentEyesInitScript() {
135
+ return `(function() {
136
+ if (window.__leapfrog_eyes_initialized) return;
137
+ window.__leapfrog_eyes_initialized = true;
138
+
139
+ function init() {
140
+ // ── CSS ──────────────────────────────────────────────────────────
141
+ var style = document.createElement('style');
142
+ style.setAttribute('data-leapfrog', 'true');
143
+ style.textContent = \`
144
+ #leapfrog-cursor {
145
+ position: fixed;
146
+ width: 28px;
147
+ height: 28px;
148
+ pointer-events: none;
149
+ z-index: 2147483646;
150
+ transition: left 0.04s linear, top 0.04s linear, opacity 0.3s ease;
151
+ opacity: 0;
152
+ filter: drop-shadow(0 1px 3px rgba(0,0,0,0.4)) drop-shadow(0 0 8px rgba(34,197,94,0.3));
153
+ }
154
+ #leapfrog-cursor-ring {
155
+ position: fixed;
156
+ width: 36px;
157
+ height: 36px;
158
+ border-radius: 50%;
159
+ border: 2px solid rgba(34, 197, 94, 0.3);
160
+ pointer-events: none;
161
+ z-index: 2147483646;
162
+ transform: translate(-50%, -50%);
163
+ transition: left 0.08s ease-out, top 0.08s ease-out, opacity 0.3s ease;
164
+ opacity: 0;
165
+ }
166
+ #leapfrog-scroll-indicator {
167
+ position: fixed;
168
+ right: 16px;
169
+ top: 50%;
170
+ width: 36px;
171
+ height: 36px;
172
+ border-radius: 50%;
173
+ background: rgba(34, 197, 94, 0.7);
174
+ color: #fff;
175
+ font-size: 20px;
176
+ line-height: 36px;
177
+ text-align: center;
178
+ pointer-events: none;
179
+ z-index: 2147483646;
180
+ opacity: 0;
181
+ transition: opacity 0.15s ease-out;
182
+ transform: translateY(-50%);
183
+ }
184
+ \`;
185
+ (document.head || document.documentElement).appendChild(style);
186
+
187
+ // ── Agent Cursor (dot + trailing ring) ──────────────────────────
188
+ var cursor = document.createElement('div');
189
+ cursor.id = 'leapfrog-cursor';
190
+ cursor.setAttribute('data-leapfrog', 'true');
191
+ cursor.innerHTML = '<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 2L12 26L15 15L26 12L2 2Z" fill="#22c55e" stroke="#166534" stroke-width="1.5" stroke-linejoin="round"/></svg>';
192
+ (document.body || document.documentElement).appendChild(cursor);
193
+
194
+ var ring = document.createElement('div');
195
+ ring.id = 'leapfrog-cursor-ring';
196
+ ring.setAttribute('data-leapfrog', 'true');
197
+ (document.body || document.documentElement).appendChild(ring);
198
+
199
+ var cursorTimeout;
200
+ document.addEventListener('mousemove', function(e) {
201
+ cursor.style.left = e.clientX + 'px';
202
+ cursor.style.top = e.clientY + 'px';
203
+ cursor.style.opacity = '1';
204
+ ring.style.left = e.clientX + 'px';
205
+ ring.style.top = e.clientY + 'px';
206
+ ring.style.opacity = '1';
207
+ clearTimeout(cursorTimeout);
208
+ cursorTimeout = setTimeout(function() {
209
+ cursor.style.opacity = '0';
210
+ ring.style.opacity = '0';
211
+ }, 3000);
212
+ }, true);
213
+
214
+ // ── Scroll Indicator ────────────────────────────────────────────
215
+ var scrollArrow = document.createElement('div');
216
+ scrollArrow.id = 'leapfrog-scroll-indicator';
217
+ scrollArrow.setAttribute('data-leapfrog', 'true');
218
+ (document.body || document.documentElement).appendChild(scrollArrow);
219
+
220
+ var scrollFadeTimeout;
221
+ document.addEventListener('wheel', function(e) {
222
+ scrollArrow.textContent = e.deltaY > 0 ? '\\u25BC' : '\\u25B2';
223
+ scrollArrow.style.opacity = '1';
224
+ clearTimeout(scrollFadeTimeout);
225
+ scrollFadeTimeout = setTimeout(function() { scrollArrow.style.opacity = '0'; }, 400);
226
+ }, true);
227
+ }
228
+
229
+ // Defer until body exists — init scripts can run before DOM is ready
230
+ if (document.body) {
231
+ init();
232
+ } else {
233
+ document.addEventListener('DOMContentLoaded', init);
234
+ }
235
+ })();`;
236
+ }
127
237
  /** Legacy single-call version (sync scroll only, no zoom). */
128
238
  export function getScrollToTargetScript(selector) {
129
239
  const escaped = selector.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leapfrog-mcp",
3
- "version": "0.7.0",
3
+ "version": "0.7.2",
4
4
  "description": "Multi-session browser MCP for AI agents — 36 tools, stealth, persistent auth, code-first scripts, API sniffer, agent intelligence",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",