pi-chrome 0.15.23 → 0.15.24

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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable user-facing changes to `pi-chrome`.
4
4
 
5
+ ## 0.15.24 — 2026-05-16
6
+
7
+ - **Unload Chrome tools on lock.** `chrome_*` tools now deactivate when `/chrome revoke` runs or timed authorization expires, keeping the prompt/tool list small after Chrome control locks again.
8
+
5
9
  ## 0.15.23 — 2026-05-16
6
10
 
7
11
  - **Attribution.** The 0.15.22 features below are pulled from Dani Bednarski's fork (`DaniBedz/pi-chrome`). Thank you, Dani.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Pi Chrome Connector",
4
- "version": "0.15.23",
4
+ "version": "0.15.24",
5
5
  "description": "Lets Pi control tabs in Chrome via a local connector at 127.0.0.1.",
6
6
  "permissions": [
7
7
  "tabs",
@@ -441,6 +441,28 @@ class ChromeProfileBridge {
441
441
  const tabActionValues = ["list", "new", "activate", "close", "version"] as const;
442
442
  const imageFormatValues = ["png", "jpeg"] as const;
443
443
  const waitForValues = ["selector", "expression"] as const;
444
+ const CHROME_TOOL_NAMES = [
445
+ "chrome_launch",
446
+ "chrome_tab",
447
+ "chrome_snapshot",
448
+ "chrome_navigate",
449
+ "chrome_evaluate",
450
+ "chrome_click",
451
+ "chrome_type",
452
+ "chrome_fill",
453
+ "chrome_key",
454
+ "chrome_wait_for",
455
+ "chrome_list_console_messages",
456
+ "chrome_list_network_requests",
457
+ "chrome_get_network_request",
458
+ "chrome_screenshot",
459
+ "chrome_hover",
460
+ "chrome_drag",
461
+ "chrome_tap",
462
+ "chrome_scroll",
463
+ "chrome_upload_file",
464
+ ] as const;
465
+ const CHROME_TOOL_NAME_SET = new Set<string>(CHROME_TOOL_NAMES);
444
466
 
445
467
  function StringEnum<T extends readonly [string, ...string[]]>(values: T) {
446
468
  return Type.Union(values.map((value) => Type.Literal(value)) as [ReturnType<typeof Type.Literal>, ...ReturnType<typeof Type.Literal>[]]);
@@ -464,6 +486,30 @@ export default function (pi: ExtensionAPI): void {
464
486
  let backgroundDefault = false;
465
487
  let chromeAuthorizedUntil: number | "indefinite" | undefined;
466
488
  let chromeToolsRegistered = false;
489
+ let authExpiryTimer: NodeJS.Timeout | undefined;
490
+
491
+ const clearAuthExpiryTimer = (): void => {
492
+ if (!authExpiryTimer) return;
493
+ clearTimeout(authExpiryTimer);
494
+ authExpiryTimer = undefined;
495
+ };
496
+
497
+ const activeToolNamesWithoutChrome = (): string[] => pi.getActiveTools().filter((name) => !CHROME_TOOL_NAME_SET.has(name));
498
+
499
+ const activateChromeTools = (): void => {
500
+ registerChromeTools(pi);
501
+ pi.setActiveTools([...new Set([...pi.getActiveTools(), ...CHROME_TOOL_NAMES])]);
502
+ };
503
+
504
+ const deactivateChromeTools = (): void => {
505
+ pi.setActiveTools(activeToolNamesWithoutChrome());
506
+ };
507
+
508
+ const lockChromeControl = (): void => {
509
+ clearAuthExpiryTimer();
510
+ chromeAuthorizedUntil = undefined;
511
+ deactivateChromeTools();
512
+ };
467
513
 
468
514
  const authSummary = (): string => {
469
515
  if (chromeAuthorizedUntil === "indefinite") return "authorized indefinitely";
@@ -477,7 +523,7 @@ export default function (pi: ExtensionAPI): void {
477
523
  const chromeControlAuthorized = (): boolean => {
478
524
  if (chromeAuthorizedUntil === "indefinite") return true;
479
525
  if (typeof chromeAuthorizedUntil === "number" && chromeAuthorizedUntil > Date.now()) return true;
480
- chromeAuthorizedUntil = undefined;
526
+ if (chromeAuthorizedUntil !== undefined) lockChromeControl();
481
527
  return false;
482
528
  };
483
529
 
@@ -495,6 +541,21 @@ export default function (pi: ExtensionAPI): void {
495
541
  }
496
542
  };
497
543
 
544
+ const scheduleAuthExpiry = (ctx: ExtensionContext, until: number | "indefinite"): void => {
545
+ clearAuthExpiryTimer();
546
+ if (until === "indefinite") return;
547
+ authExpiryTimer = setTimeout(() => {
548
+ if (chromeAuthorizedUntil !== until) return;
549
+ try {
550
+ lockChromeControl();
551
+ ctx.ui.notify("Chrome control authorization expired. Run /chrome authorize to allow chrome_* tools again.", "info");
552
+ updateChromeStatus(ctx);
553
+ } catch (error) {
554
+ console.warn(`Failed to expire pi-chrome authorization cleanly: ${(error as Error).message}`);
555
+ }
556
+ }, Math.max(0, until - Date.now()));
557
+ };
558
+
498
559
  const authorizedBridgeSend = (action: string, params: Record<string, unknown>, timeoutMs = DEFAULT_TIMEOUT_MS, signal?: AbortSignal): Promise<unknown> => {
499
560
  requireChromeControlAuthorized();
500
561
  return bridge.send(action, params, timeoutMs, signal);
@@ -520,6 +581,7 @@ export default function (pi: ExtensionAPI): void {
520
581
  });
521
582
 
522
583
  pi.on("session_shutdown", () => {
584
+ clearAuthExpiryTimer();
523
585
  bridge.stop();
524
586
  if (globalState[PI_CHROME_GLOBAL_KEY]?.token === instanceToken) {
525
587
  delete globalState[PI_CHROME_GLOBAL_KEY];
@@ -653,8 +715,9 @@ Usage rules:
653
715
  ctx.ui.notify("Chrome control remains locked.", "info");
654
716
  return;
655
717
  }
656
- registerChromeTools(pi);
657
718
  chromeAuthorizedUntil = until;
719
+ activateChromeTools();
720
+ scheduleAuthExpiry(ctx, until);
658
721
  ctx.ui.notify(`Chrome control authorized for ${label}.`, "info");
659
722
  updateChromeStatus(ctx);
660
723
  };
@@ -677,7 +740,7 @@ Usage rules:
677
740
  };
678
741
 
679
742
  const revokeHandler = (ctx: ExtensionContext) => {
680
- chromeAuthorizedUntil = undefined;
743
+ lockChromeControl();
681
744
  ctx.ui.notify("Chrome control locked. Run /chrome authorize to allow chrome_* tools again.", "info");
682
745
  updateChromeStatus(ctx);
683
746
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-chrome",
3
- "version": "0.15.23",
3
+ "version": "0.15.24",
4
4
  "scripts": {
5
5
  "version": "node scripts/sync-manifest-version.js",
6
6
  "prepublishOnly": "node scripts/sync-manifest-version.js"