feat(connect): vendor MV3 connect extension (adapted from openclaw-browser-relay)
First step toward zero-confirmation direct connect to the user's real Chrome: Chrome 136 killed --remote-debugging-port on the default profile, so the only sanctioned way to drive the user's live logged-in window is an extension using chrome.debugger (same approach as Codex/Claude, whose extensions are closed). Vendors the MIT-licensed openclaw-browser-relay extension into extensions/ab-connect/, rebranded to "agent-browser connect" (NOTICE.md keeps attribution). It already handles the hard parts: chrome.debugger auto-attach all tabs, new-tab auto-attach, MV3 service-worker keepalive (alarms) + reconnect, sessionId↔tab mapping, token auth, and a CDP-over-WebSocket envelope (connect handshake / forwardCDPCommand / forwardCDPEvent / ping-pong). Inert for now — not wired. Next: an abs-daemon relay that speaks this envelope and bridges it to the existing CdpClient (raw CDP), then a `connect` command.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
export function reconnectDelayMs(
|
||||
attempt,
|
||||
opts = { baseMs: 1000, maxMs: 30000, jitterMs: 1000, random: Math.random },
|
||||
) {
|
||||
const baseMs = Number.isFinite(opts.baseMs) ? opts.baseMs : 1000;
|
||||
const maxMs = Number.isFinite(opts.maxMs) ? opts.maxMs : 30000;
|
||||
const jitterMs = Number.isFinite(opts.jitterMs) ? opts.jitterMs : 1000;
|
||||
const random = typeof opts.random === "function" ? opts.random : Math.random;
|
||||
const safeAttempt = Math.max(0, Number.isFinite(attempt) ? attempt : 0);
|
||||
const backoff = Math.min(baseMs * 2 ** safeAttempt, maxMs);
|
||||
return backoff + Math.max(0, jitterMs) * random();
|
||||
}
|
||||
|
||||
export async function deriveRelayToken(gatewayToken, port) {
|
||||
const enc = new TextEncoder();
|
||||
const key = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
enc.encode(gatewayToken),
|
||||
{ name: "HMAC", hash: "SHA-256" },
|
||||
false,
|
||||
["sign"],
|
||||
);
|
||||
const sig = await crypto.subtle.sign(
|
||||
"HMAC",
|
||||
key,
|
||||
enc.encode(`openclaw-extension-relay-v1:${port}`),
|
||||
);
|
||||
return [...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
||||
}
|
||||
|
||||
export async function buildRelayWsUrl(port, gatewayToken) {
|
||||
const token = String(gatewayToken || "").trim();
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
"Missing gatewayToken in extension settings (chrome.storage.local.gatewayToken)",
|
||||
);
|
||||
}
|
||||
const relayToken = await deriveRelayToken(token, port);
|
||||
return `ws://127.0.0.1:${port}/extension?token=${encodeURIComponent(relayToken)}`;
|
||||
}
|
||||
|
||||
export function isRetryableReconnectError(err) {
|
||||
const message = err instanceof Error ? err.message : String(err || "");
|
||||
if (message.includes("Missing gatewayToken")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user