pi-chrome 0.11.2 → 0.11.3
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Pi Chrome Connector",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.3",
|
|
5
5
|
"description": "Lets Pi control tabs in Chrome via a local connector at 127.0.0.1.",
|
|
6
6
|
"permissions": ["tabs", "scripting", "storage", "activeTab", "alarms", "webNavigation", "debugger"],
|
|
7
7
|
"host_permissions": ["<all_urls>", "http://127.0.0.1:17318/*"],
|
|
@@ -169,7 +169,7 @@ async function cdpMoveTo(tabId, x, y) {
|
|
|
169
169
|
const entry = attachedTabs.get(tabId);
|
|
170
170
|
const startX = entry?.pointer?.x ?? Math.max(20, Math.min(400, x - 200));
|
|
171
171
|
const startY = entry?.pointer?.y ?? Math.max(20, Math.min(400, y - 200));
|
|
172
|
-
const n = Math.max(
|
|
172
|
+
const n = Math.max(18, Math.min(42, Math.round(Math.hypot(x - startX, y - startY) / 18)));
|
|
173
173
|
for (let i = 1; i <= n; i++) {
|
|
174
174
|
const t = i / n;
|
|
175
175
|
const ease = t * t * (3 - 2 * t);
|
|
@@ -368,13 +368,13 @@ async function trustedScroll(params) {
|
|
|
368
368
|
const y = resolved.rect ? resolved.rect.top + Math.min(resolved.rect.height, 600) / 2 : resolved.y;
|
|
369
369
|
const totalY = params.deltaY || 0, totalX = params.deltaX || 0;
|
|
370
370
|
// Per-event delta cap so IntersectionObserver / scroll-driven animations get gradient samples.
|
|
371
|
-
// A
|
|
372
|
-
|
|
371
|
+
// A trackpad inertia tick often delivers ~10-30px per frame; using ~25px keeps small-target
|
|
372
|
+
// visibility transitions detectable while not making large scrolls take forever.
|
|
373
|
+
const MAX_STEP = 25;
|
|
373
374
|
const peak = Math.max(Math.abs(totalY), Math.abs(totalX));
|
|
374
|
-
//
|
|
375
|
-
// first event is ~1.5× average. Choose n so even the peak event stays under MAX_STEP.
|
|
375
|
+
// Front-loaded weights peak at ~1.5× average, so choose n so peak event stays under MAX_STEP.
|
|
376
376
|
const minN = Math.ceil(peak * 1.5 / MAX_STEP);
|
|
377
|
-
const n = Math.max(6, Math.min(
|
|
377
|
+
const n = Math.max(6, Math.min(200, params.steps || Math.max(minN, 12)));
|
|
378
378
|
// Front-loaded but smooth weights: w[i] = 1 + 0.5 * (1 - i/(n-1)) so the first event has
|
|
379
379
|
// weight 1.5, the last has 1.0, average ~1.25; redistribution stays predictable.
|
|
380
380
|
const w = [];
|
|
@@ -509,7 +509,7 @@ Usage rules:
|
|
|
509
509
|
lines.push(`… Skipped MAIN-world capability checks because the loaded extension is stale.`);
|
|
510
510
|
}
|
|
511
511
|
|
|
512
|
-
//
|
|
512
|
+
// Real-input mode probe (plain English for the user).
|
|
513
513
|
if (extensionAlive && !versionMismatch) {
|
|
514
514
|
try {
|
|
515
515
|
const status = (await bridge.send("trusted.status", {}, 5_000)) as {
|
|
@@ -518,19 +518,20 @@ Usage rules:
|
|
|
518
518
|
permissionGranted?: boolean;
|
|
519
519
|
};
|
|
520
520
|
if (status.permissionGranted) {
|
|
521
|
-
const
|
|
521
|
+
const banner = status.attachedTabs && status.attachedTabs.length ? ` (yellow banner up on ${status.attachedTabs.length} tab(s))` : "";
|
|
522
522
|
const note =
|
|
523
523
|
status.mode === "auto"
|
|
524
|
-
? "
|
|
524
|
+
? " Clicks/keys are quiet by default; if a site rejects a quiet click, pi-chrome retries it once with a real-looking click. Yellow 'pi-chrome is controlling Chrome' banner shows only when that retry happens."
|
|
525
525
|
: status.mode === "on"
|
|
526
|
-
? "
|
|
527
|
-
: "
|
|
528
|
-
|
|
526
|
+
? " Every click and keystroke uses a real-looking event. Yellow 'pi-chrome is controlling Chrome' banner stays up on every tab pi-chrome touches."
|
|
527
|
+
: " All clicks are quiet, no yellow banner. Some sites (sign-ins, copy buttons, file pickers, paywalls) may silently ignore them. Switch to /chrome-trusted auto if a site isn't responding.";
|
|
528
|
+
const label = status.mode === "auto" ? "auto (smart upgrade)" : status.mode === "on" ? "on (always real-looking)" : "off (always quiet)";
|
|
529
|
+
lines.push(`✓ Click mode: ${label}${banner}.${note}`);
|
|
529
530
|
} else {
|
|
530
|
-
lines.push(`⚠
|
|
531
|
+
lines.push(`⚠ Can't send real-looking clicks yet — the companion extension is missing a permission. Open chrome://extensions, click reload on 'Pi Chrome Connector', and accept the new permission prompt.`);
|
|
531
532
|
}
|
|
532
533
|
} catch (error) {
|
|
533
|
-
lines.push(`⚠
|
|
534
|
+
lines.push(`⚠ Couldn't check click mode: ${(error as Error).message}`);
|
|
534
535
|
}
|
|
535
536
|
}
|
|
536
537
|
|
|
@@ -540,13 +541,13 @@ Usage rules:
|
|
|
540
541
|
|
|
541
542
|
pi.registerCommand("chrome-trusted", {
|
|
542
543
|
description:
|
|
543
|
-
"
|
|
544
|
+
"Choose how realistically pi-chrome should drive Chrome. Real-looking clicks/keys unlock things like copy-to-clipboard buttons, file pickers, and sign-in pages, but show a yellow 'pi-chrome is controlling Chrome' banner. Three modes:\n auto (default) — quiet by default; auto-upgrade when a site blocks the quiet click.\n off — always quiet, no banner; some sites won't accept these clicks.\n on — always real-looking, banner stays up the whole session.\n status — show the current mode.",
|
|
544
545
|
getArgumentCompletions: (prefix) => {
|
|
545
546
|
const items = [
|
|
546
|
-
{ value: "
|
|
547
|
-
{ value: "off", label: "off", description: "
|
|
548
|
-
{ value: "
|
|
549
|
-
{ value: "status", label: "status", description: "Show current
|
|
547
|
+
{ value: "auto", label: "auto", description: "Default. Quiet clicks; upgrade to real ones only when a site rejects them." },
|
|
548
|
+
{ value: "off", label: "off", description: "Always quiet. No banner. Some sites won't accept the clicks." },
|
|
549
|
+
{ value: "on", label: "on", description: "Always real-looking clicks. Yellow banner stays up. Best for stubborn sites." },
|
|
550
|
+
{ value: "status", label: "status", description: "Show the current mode." },
|
|
550
551
|
];
|
|
551
552
|
const lowered = prefix.toLowerCase();
|
|
552
553
|
const matches = items.filter((item) => item.value.startsWith(lowered));
|
|
@@ -560,37 +561,43 @@ Usage rules:
|
|
|
560
561
|
try {
|
|
561
562
|
status = (await bridge.send("trusted.status", {}, 5_000)) as typeof status;
|
|
562
563
|
} catch (error) {
|
|
563
|
-
ctx.ui.notify(`
|
|
564
|
+
ctx.ui.notify(`Couldn't check current mode: ${(error as Error).message}`, "warning");
|
|
564
565
|
return;
|
|
565
566
|
}
|
|
566
567
|
if (!status) return;
|
|
567
568
|
|
|
568
569
|
if (!status.permissionGranted) {
|
|
569
570
|
ctx.ui.notify(
|
|
570
|
-
"chrome
|
|
571
|
+
"pi-chrome can't drive real-looking clicks yet — the companion extension is missing a permission. Open chrome://extensions, click reload on 'Pi Chrome Connector', and accept the new permission prompt that appears.",
|
|
571
572
|
"warning",
|
|
572
573
|
);
|
|
573
574
|
return;
|
|
574
575
|
}
|
|
575
576
|
|
|
576
|
-
const
|
|
577
|
+
const MODE_NAMES: Record<string, string> = {
|
|
578
|
+
auto: "auto (smart upgrade)",
|
|
579
|
+
off: "off (always quiet)",
|
|
580
|
+
on: "on (always real-looking)",
|
|
581
|
+
};
|
|
582
|
+
const friendly = (m: string) => MODE_NAMES[m] ?? m;
|
|
583
|
+
const attached = status.attachedTabs?.length ? ` — yellow banner currently up on ${status.attachedTabs.length} tab(s)` : "";
|
|
577
584
|
const current = status.mode;
|
|
578
585
|
|
|
579
586
|
let target = rawArg;
|
|
580
587
|
if (target === "status") {
|
|
581
|
-
ctx.ui.notify(`
|
|
588
|
+
ctx.ui.notify(`Current mode: ${friendly(current)}${attached}`, "info");
|
|
582
589
|
return;
|
|
583
590
|
}
|
|
584
591
|
if (!target) {
|
|
585
|
-
// Interactive picker.
|
|
592
|
+
// Interactive picker. Plain-English descriptions; no jargon.
|
|
586
593
|
const options = [
|
|
587
|
-
`auto${current === "auto" ? " (current)" : ""} — default;
|
|
588
|
-
`off${current === "off" ? " (current)" : ""} —
|
|
589
|
-
`on${current === "on" ? " (current)" : ""} — every
|
|
590
|
-
`status —
|
|
594
|
+
`auto${current === "auto" ? " (current)" : ""} — quiet by default; if a site rejects a quiet click, retry it once with a real-looking click. Yellow banner appears only when needed. Recommended for everyday use.`,
|
|
595
|
+
`off${current === "off" ? " (current)" : ""} — always quiet. No yellow banner, ever. Fast and unobtrusive, but some sites (sign-in pages, copy-to-clipboard buttons, file pickers, paywalls) will silently ignore the click.`,
|
|
596
|
+
`on${current === "on" ? " (current)" : ""} — every click and keystroke uses a real-looking event. Yellow 'pi-chrome is controlling Chrome' banner stays at the top of every Chrome window the whole session. Best when working a stubborn site for a long stretch.`,
|
|
597
|
+
`status — just show me which mode is on right now.`,
|
|
591
598
|
];
|
|
592
599
|
const picked = await ctx.ui.select(
|
|
593
|
-
`
|
|
600
|
+
`How realistic should pi-chrome's clicks be? (current: ${friendly(current)}${attached})`,
|
|
594
601
|
options,
|
|
595
602
|
);
|
|
596
603
|
if (!picked) return; // cancelled
|
|
@@ -598,29 +605,29 @@ Usage rules:
|
|
|
598
605
|
else if (picked.startsWith("off")) target = "off";
|
|
599
606
|
else if (picked.startsWith("auto")) target = "auto";
|
|
600
607
|
else if (picked.startsWith("status")) {
|
|
601
|
-
ctx.ui.notify(`
|
|
608
|
+
ctx.ui.notify(`Current mode: ${friendly(current)}${attached}`, "info");
|
|
602
609
|
return;
|
|
603
610
|
}
|
|
604
611
|
}
|
|
605
612
|
|
|
606
613
|
if (!["on", "off", "auto"].includes(target)) {
|
|
607
|
-
ctx.ui.notify(`Unknown
|
|
614
|
+
ctx.ui.notify(`Unknown choice '${rawArg}'. Pick one of: auto | off | on | status, or just run /chrome-trusted with no argument.`, "warning");
|
|
608
615
|
return;
|
|
609
616
|
}
|
|
610
617
|
|
|
611
618
|
if (target === current) {
|
|
612
|
-
ctx.ui.notify(`
|
|
619
|
+
ctx.ui.notify(`Already in ${friendly(current)} mode.`, "info");
|
|
613
620
|
return;
|
|
614
621
|
}
|
|
615
622
|
|
|
616
|
-
// Extra confirmation only on first-time "on" (warn about banner).
|
|
617
|
-
if (target === "on" && current
|
|
623
|
+
// Extra confirmation only on first-time "on" (warn about persistent banner).
|
|
624
|
+
if (target === "on" && current !== "on") {
|
|
618
625
|
const ok = await ctx.ui.confirm(
|
|
619
|
-
"
|
|
620
|
-
"
|
|
626
|
+
"Always use real-looking clicks?",
|
|
627
|
+
"Every click and keystroke pi-chrome sends will now look like a real human action to websites. This unlocks copy-to-clipboard buttons, sign-in pages, file pickers, fullscreen, autoplay, and most bot-protected sites.\n\nThe tradeoff: Chrome will pin a yellow bar at the top of every Chrome window saying 'pi-chrome is controlling Chrome'. The bar stays visible for the rest of your pi session (or until you switch back to auto/off). Clicking 'Cancel' on the bar interrupts pi-chrome.",
|
|
621
628
|
);
|
|
622
629
|
if (!ok) {
|
|
623
|
-
ctx.ui.notify("
|
|
630
|
+
ctx.ui.notify("Mode unchanged.", "info");
|
|
624
631
|
return;
|
|
625
632
|
}
|
|
626
633
|
}
|
|
@@ -629,16 +636,16 @@ Usage rules:
|
|
|
629
636
|
const result = (await bridge.send("trusted.mode", { mode: target }, 5_000)) as { mode: string };
|
|
630
637
|
if (result.mode === "on") {
|
|
631
638
|
ctx.ui.notify(
|
|
632
|
-
"
|
|
639
|
+
"On. Every click and keystroke now looks real to websites. The yellow 'pi-chrome is controlling Chrome' banner will appear on every tab pi-chrome touches.",
|
|
633
640
|
"info",
|
|
634
641
|
);
|
|
635
642
|
} else if (result.mode === "off") {
|
|
636
|
-
ctx.ui.notify("
|
|
643
|
+
ctx.ui.notify("Off. All clicks are quiet now, no yellow banner. Note: some sites (sign-ins, copy buttons, file pickers, paywalls) may silently ignore these clicks.", "info");
|
|
637
644
|
} else {
|
|
638
|
-
ctx.ui.notify("
|
|
645
|
+
ctx.ui.notify("Auto. Clicks stay quiet by default; pi-chrome will only switch to real-looking clicks when a site rejects a quiet one. The yellow banner will appear only when that retry happens.", "info");
|
|
639
646
|
}
|
|
640
647
|
} catch (error) {
|
|
641
|
-
ctx.ui.notify(`
|
|
648
|
+
ctx.ui.notify(`Couldn't switch mode: ${(error as Error).message}`, "warning");
|
|
642
649
|
}
|
|
643
650
|
},
|
|
644
651
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-chrome",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "Drive your existing logged-in Chrome from Pi — no re-login, no throwaway profile, watch the agent work in real time (or toggle quiet background mode).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|