pi-chrome 0.14.0 → 0.14.1
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.14.
|
|
4
|
+
"version": "0.14.1",
|
|
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/*"],
|
|
@@ -60,6 +60,13 @@ async function maybeUpgradeToTrusted(kind, params, syntheticResult, trustedFn) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
// Last few attach failures, kept for /chrome doctor + trusted.debug diagnostics.
|
|
64
|
+
const attachDebugLog = [];
|
|
65
|
+
function recordAttachEvent(entry) {
|
|
66
|
+
attachDebugLog.push({ ...entry, t: Date.now() });
|
|
67
|
+
if (attachDebugLog.length > 20) attachDebugLog.shift();
|
|
68
|
+
}
|
|
69
|
+
|
|
63
70
|
async function attachDebugger(tabId) {
|
|
64
71
|
if (!chrome.debugger) throw new Error("chrome.debugger API unavailable; reload the extension to grant the new permission");
|
|
65
72
|
if (attachedTabs.has(tabId)) {
|
|
@@ -67,28 +74,75 @@ async function attachDebugger(tabId) {
|
|
|
67
74
|
entry.detachAt = Date.now() + TRUSTED_IDLE_DETACH_MS;
|
|
68
75
|
return entry;
|
|
69
76
|
}
|
|
77
|
+
// Before each attach, force-detach any stale CDP target this extension owns on the tab.
|
|
78
|
+
// Chrome sometimes keeps a half-dead session around (extension reload mid-attach, etc.) and
|
|
79
|
+
// surfaces it as "Cannot access a chrome-extension://" on the next attach attempt.
|
|
70
80
|
try {
|
|
71
|
-
await chrome.debugger.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
const targets = await new Promise((resolve) => chrome.debugger.getTargets((t) => resolve(t || [])));
|
|
82
|
+
for (const tgt of targets) {
|
|
83
|
+
if (tgt.tabId === tabId && tgt.attached) {
|
|
84
|
+
recordAttachEvent({ kind: "stale-target-found", tabId, target: { id: tgt.id, type: tgt.type, url: tgt.url, extensionId: tgt.extensionId } });
|
|
85
|
+
try { await chrome.debugger.detach({ tabId }); } catch {}
|
|
86
|
+
await sleep(80);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {}
|
|
91
|
+
const attemptAttach = async () => {
|
|
92
|
+
try {
|
|
93
|
+
await chrome.debugger.attach({ tabId }, CDP_VERSION);
|
|
94
|
+
return null;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
return error;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
let err = await attemptAttach();
|
|
100
|
+
if (err) {
|
|
101
|
+
const msg = String(err?.message || err);
|
|
77
102
|
const transient = /Cannot access a chrome-extension|Cannot access contents of|No tab with id|Debugger is not attached|Another debugger|Target closed/i.test(msg);
|
|
78
|
-
|
|
103
|
+
const tabSnapshot = await chrome.tabs.get(tabId).catch(() => null);
|
|
104
|
+
recordAttachEvent({ kind: "attach-failed", tabId, message: msg, tabUrl: tabSnapshot?.url, transient });
|
|
105
|
+
if (!transient) throw err;
|
|
106
|
+
if (!tabSnapshot || (tabSnapshot.url || "").startsWith("chrome://") || (tabSnapshot.url || "").startsWith("chrome-extension://")) {
|
|
107
|
+
throw new Error(`Chrome can't attach the debugger to this tab (${tabSnapshot?.url ?? "unknown"}). Open a normal http(s) tab and try again.`);
|
|
108
|
+
}
|
|
79
109
|
await sleep(180);
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
110
|
+
err = await attemptAttach();
|
|
111
|
+
if (err) {
|
|
112
|
+
recordAttachEvent({ kind: "attach-retry-failed", tabId, message: String(err.message || err), tabUrl: tabSnapshot?.url });
|
|
113
|
+
// One more try after a longer settle. Some Chrome builds need ~500ms after a navigation
|
|
114
|
+
// for content-script registration on the tab to drain before chrome.debugger.attach
|
|
115
|
+
// will accept the target.
|
|
116
|
+
await sleep(500);
|
|
117
|
+
err = await attemptAttach();
|
|
118
|
+
if (err) {
|
|
119
|
+
recordAttachEvent({ kind: "attach-retry2-failed", tabId, message: String(err.message || err), tabUrl: tabSnapshot?.url });
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
83
122
|
}
|
|
84
|
-
await chrome.debugger.attach({ tabId }, CDP_VERSION);
|
|
85
123
|
}
|
|
124
|
+
recordAttachEvent({ kind: "attached", tabId });
|
|
86
125
|
// Seed pointer in a plausible "just left the address bar" location.
|
|
87
126
|
const entry = { detachAt: Date.now() + TRUSTED_IDLE_DETACH_MS, pointer: { x: 120 + Math.random() * 200, y: 80 + Math.random() * 120 } };
|
|
88
127
|
attachedTabs.set(tabId, entry);
|
|
89
128
|
return entry;
|
|
90
129
|
}
|
|
91
130
|
|
|
131
|
+
async function trustedDebug(params) {
|
|
132
|
+
const tab = params?.targetId ? await chrome.tabs.get(Number(params.targetId)).catch(() => null) : null;
|
|
133
|
+
let targets = [];
|
|
134
|
+
try { targets = await new Promise((resolve) => chrome.debugger.getTargets((t) => resolve(t || []))); } catch {}
|
|
135
|
+
return {
|
|
136
|
+
extensionVersion: chrome.runtime.getManifest().version,
|
|
137
|
+
extensionId: chrome.runtime.id,
|
|
138
|
+
trustedMode: TRUSTED_MODE,
|
|
139
|
+
attachedTabs: Array.from(attachedTabs.keys()),
|
|
140
|
+
requestedTab: tab ? { id: tab.id, url: tab.url, status: tab.status, title: tab.title } : null,
|
|
141
|
+
cdpTargets: targets,
|
|
142
|
+
recentAttachEvents: attachDebugLog.slice(),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
92
146
|
async function detachDebugger(tabId) {
|
|
93
147
|
if (!attachedTabs.has(tabId)) return;
|
|
94
148
|
attachedTabs.delete(tabId);
|
|
@@ -639,6 +693,8 @@ async function dispatch(action, params) {
|
|
|
639
693
|
return setTrustedMode(params.mode);
|
|
640
694
|
case "trusted.status":
|
|
641
695
|
return trustedStatus();
|
|
696
|
+
case "trusted.debug":
|
|
697
|
+
return trustedDebug(params);
|
|
642
698
|
case "page.console.list":
|
|
643
699
|
return executeInTab(params, listConsoleMessages, [params.clear === true]);
|
|
644
700
|
case "page.network.list":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-chrome",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.1",
|
|
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",
|