pi-chrome 0.3.2 → 0.4.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.
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# pi-chrome
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/pi-chrome)
|
|
4
|
+
|
|
3
5
|
Control the Chrome profile you already use from Pi.
|
|
4
6
|
|
|
5
7
|
`pi-chrome` gives Pi agents browser tools for your **real Chrome windows, tabs, and authenticated sessions**. It uses a companion Chrome extension instead of the Chrome DevTools Protocol (CDP), so it does not launch a throwaway debug browser profile and does not require re-signing into the apps you already have open.
|
|
@@ -25,6 +27,10 @@ For local development from a checkout:
|
|
|
25
27
|
pi install ./pi-chrome
|
|
26
28
|
```
|
|
27
29
|
|
|
30
|
+
### Why an unpacked Chrome extension?
|
|
31
|
+
|
|
32
|
+
The Chrome Web Store does not allow extensions that talk to a local bridge controlled by another tool, so `pi-chrome` ships its companion as an unpacked extension you load yourself. The source is small, MIT-licensed, and lives in `extensions/chrome-profile-bridge/browser-extension/` next to this README — read it before loading.
|
|
33
|
+
|
|
28
34
|
## First-time setup
|
|
29
35
|
|
|
30
36
|
In Pi, run:
|
|
@@ -93,6 +99,32 @@ Local web app repro with screenshot:
|
|
|
93
99
|
Use chrome_tab list to find my localhost app, inspect it with chrome_snapshot, navigate through the bug repro flow, and save a screenshot when you reach the broken state.
|
|
94
100
|
```
|
|
95
101
|
|
|
102
|
+
## Recipes
|
|
103
|
+
|
|
104
|
+
Copy-paste these into Pi after setup. Each one uses tabs you already have open and accounts you are already signed into.
|
|
105
|
+
|
|
106
|
+
- **PR triage:** "Use chrome_tab list to find my GitHub notifications tab, snapshot it, and summarize PRs needing my review."
|
|
107
|
+
- **Linear standup:** "Open my Linear current cycle in the active tab, snapshot it, and write me a 5-bullet standup."
|
|
108
|
+
- **Bug repro with evidence:** "Open the staging app I'm already signed into, reproduce <bug>, and save a screenshot of each step under ./repro/."
|
|
109
|
+
- **Form auto-fill (no submit):** "Open <vendor> portal, fill the new-vendor form from this JSON, but stop before submit."
|
|
110
|
+
- **Admin cross-check:** "Across my Stripe / Postmark / our admin tabs, find any user where state disagrees."
|
|
111
|
+
- **Local dev visual diff:** "Snapshot localhost:3000 and the staging URL of the same page; tell me what's visually different."
|
|
112
|
+
- **Auth-only data pull:** "Open my analytics dashboard tab and chrome_evaluate to extract today's KPIs from the page state."
|
|
113
|
+
|
|
114
|
+
Screenshots save under `.pi/chrome-screenshots/` by default, which composes nicely with PR demo workflows.
|
|
115
|
+
|
|
116
|
+
## Diagnostics
|
|
117
|
+
|
|
118
|
+
- `/chrome-status` — quick health check; reports the connected Chrome extension ID and version.
|
|
119
|
+
- `/chrome-doctor` — deeper diagnosis with one-line fixes for common setup failures (extension not loaded, bridge owner stale after `pi update`, version mismatch between pi-chrome and the loaded Chrome extension).
|
|
120
|
+
|
|
121
|
+
If the Chrome extension you have loaded is older than `pi-chrome` on disk, `/chrome-doctor` will tell you to reload it from `chrome://extensions`.
|
|
122
|
+
|
|
123
|
+
## Compose with
|
|
124
|
+
|
|
125
|
+
- **pi-qq** — ask side questions about what the agent saw in Chrome without polluting the main transcript: `/qq summarize what the active GitHub tab shows`.
|
|
126
|
+
- **PR demo skills** (such as `ios-pr-agent` / `ios-demo-record` workflows) — `chrome_screenshot` writes to `.pi/chrome-screenshots/` so you can attach images to PR descriptions or demo bundles.
|
|
127
|
+
|
|
96
128
|
## Tools
|
|
97
129
|
|
|
98
130
|
The package registers these Pi tools:
|
|
@@ -110,7 +142,8 @@ The package registers these Pi tools:
|
|
|
110
142
|
|
|
111
143
|
These tools are especially useful for authenticated web app debugging, repro flows, admin workflows, visual checks, and inspecting local development pages without rebuilding login state.
|
|
112
144
|
|
|
113
|
-
|
|
145
|
+
<details>
|
|
146
|
+
<summary><strong>How it works (technical details)</strong></summary>
|
|
114
147
|
|
|
115
148
|
Pi starts a local bridge on `127.0.0.1:17318`. The companion Chrome extension, installed in your normal Chrome profile, polls that local bridge for commands and executes them using Chrome extension APIs.
|
|
116
149
|
|
|
@@ -118,6 +151,8 @@ If another Pi session is already running the bridge, additional Pi sessions auto
|
|
|
118
151
|
|
|
119
152
|
This is intentionally different from CDP-based tools: the browser extension lives inside the profile you already use, so Pi can interact with existing tabs and authenticated page state.
|
|
120
153
|
|
|
154
|
+
</details>
|
|
155
|
+
|
|
121
156
|
## Security model
|
|
122
157
|
|
|
123
158
|
The companion Chrome extension runs in the Chrome profile where you install it and has broad tab/scripting permissions. Only install it from a package source you trust.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Pi Existing Chrome Profile Bridge",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"description": "Lets Pi control tabs in this existing Chrome profile via a local bridge at 127.0.0.1.",
|
|
6
6
|
"permissions": ["tabs", "scripting", "storage", "activeTab", "alarms"],
|
|
7
7
|
"host_permissions": ["<all_urls>", "http://127.0.0.1:17318/*"],
|
|
@@ -80,7 +80,12 @@ function sleep(ms) {
|
|
|
80
80
|
async function dispatch(action, params) {
|
|
81
81
|
switch (action) {
|
|
82
82
|
case "tab.version":
|
|
83
|
-
return {
|
|
83
|
+
return {
|
|
84
|
+
extensionId: chrome.runtime.id,
|
|
85
|
+
extensionVersion: chrome.runtime.getManifest().version,
|
|
86
|
+
bridgeUrl: BRIDGE_URL,
|
|
87
|
+
userAgent: navigator.userAgent,
|
|
88
|
+
};
|
|
84
89
|
case "tab.list":
|
|
85
90
|
return (await chrome.tabs.query({})).map(formatTab);
|
|
86
91
|
case "tab.new": {
|
|
@@ -46,6 +46,7 @@ type BridgeResult = {
|
|
|
46
46
|
error?: string;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
+
const PI_CHROME_VERSION = "0.4.0";
|
|
49
50
|
const DEFAULT_HOST = process.env.PI_CHROME_BRIDGE_HOST ?? "127.0.0.1";
|
|
50
51
|
const DEFAULT_PORT = Number(process.env.PI_CHROME_BRIDGE_PORT ?? "17318");
|
|
51
52
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
@@ -351,19 +352,50 @@ If chrome_* tools time out, ask the user to run /chrome-onboard, then load the b
|
|
|
351
352
|
handler: async (_args, ctx) => {
|
|
352
353
|
ctx.ui.notify("Performing Chrome bridge health check", "info");
|
|
353
354
|
try {
|
|
354
|
-
const version = (await bridge.send("tab.version", {}, 35_000)) as { extensionId?: string };
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
"info",
|
|
360
|
-
);
|
|
355
|
+
const version = (await bridge.send("tab.version", {}, 35_000)) as { extensionId?: string; extensionVersion?: string };
|
|
356
|
+
const suffix = [version.extensionId ? `ID: ${version.extensionId}` : null, version.extensionVersion ? `ext v${version.extensionVersion}` : null]
|
|
357
|
+
.filter(Boolean)
|
|
358
|
+
.join(", ");
|
|
359
|
+
ctx.ui.notify(suffix ? `Chrome profile bridge connected (${suffix})` : "Chrome profile bridge connected", "info");
|
|
361
360
|
} catch (error) {
|
|
362
361
|
ctx.ui.notify(`Chrome bridge health check failed: ${(error as Error).message}`, "warning");
|
|
363
362
|
}
|
|
364
363
|
},
|
|
365
364
|
});
|
|
366
365
|
|
|
366
|
+
pi.registerCommand("chrome-doctor", {
|
|
367
|
+
description:
|
|
368
|
+
"Diagnose Chrome bridge setup. Checks the local bridge, the companion Chrome extension, and reports a one-line fix for common failures.",
|
|
369
|
+
handler: async (_args, ctx) => {
|
|
370
|
+
const lines: string[] = [`pi-chrome v${PI_CHROME_VERSION}`];
|
|
371
|
+
const status = bridge.status();
|
|
372
|
+
lines.push(`• Local bridge: mode=${status.mode}, url=${status.url}`);
|
|
373
|
+
try {
|
|
374
|
+
const version = (await bridge.send("tab.version", {}, 8_000)) as {
|
|
375
|
+
extensionId?: string;
|
|
376
|
+
extensionVersion?: string;
|
|
377
|
+
};
|
|
378
|
+
if (version.extensionId)
|
|
379
|
+
lines.push(`✓ Companion Chrome extension responding (ID: ${version.extensionId}, ext v${version.extensionVersion ?? "unknown"})`);
|
|
380
|
+
else lines.push("✓ Companion Chrome extension responding (no extension ID reported)");
|
|
381
|
+
if (version.extensionVersion && version.extensionVersion !== PI_CHROME_VERSION) {
|
|
382
|
+
lines.push(
|
|
383
|
+
`⚠ Extension version (${version.extensionVersion}) differs from pi-chrome (${PI_CHROME_VERSION}). Reload "Pi Existing Chrome Profile Bridge" in chrome://extensions to pick up the latest service worker.`,
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
} catch (error) {
|
|
387
|
+
const message = (error as Error).message;
|
|
388
|
+
lines.push(`✗ Companion Chrome extension not responding: ${message}`);
|
|
389
|
+
if (message.includes("older pi-chrome without multi-session")) {
|
|
390
|
+
lines.push(" Fix: restart the Pi session that owns the bridge (it was started on an older pi-chrome).");
|
|
391
|
+
} else {
|
|
392
|
+
lines.push(" Fix: run /chrome-onboard, then load the bundled browser-extension folder in chrome://extensions and keep that Chrome window open.");
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
|
|
367
399
|
pi.registerCommand("chrome-foreground", {
|
|
368
400
|
description:
|
|
369
401
|
"Toggle whether chrome_* tools bring Chrome to the foreground. Foreground ON: you can watch the agent work in your browser, useful for demos, pair-driving, and debugging — tradeoff: Chrome pops up and steals focus, interrupting whatever app you were using. Foreground OFF (default): chrome_* tools act silently in the background, so your editor/terminal keeps focus and your workflow is not interrupted. Pass `on` / `off` to set explicitly, or no argument to toggle.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-chrome",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Control your existing authenticated Chrome profile from Pi with tabs, snapshots, clicks, typing, JS evaluation, waits, and screenshots \u2014 background by default.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|