openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
91 lines • 3.36 kB
JavaScript
/**
* @license
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { logger } from '../utils/logger.js';
const DEFAULT_DEBOUNCE_MS = 200;
/**
* Manages the bidirectional bridge between DevTools frontend comments
* and the MCP server notification system.
*/
export class DevToolsCommentBridge {
#onNotification;
#debounceMs;
#commentDebounceTimer;
#attachedPages = new Set();
constructor(options) {
this.#onNotification = options?.onNotification;
this.#debounceMs = options?.debounceMs ?? DEFAULT_DEBOUNCE_MS;
}
isAttached(devtoolsPage) {
return this.#attachedPages.has(devtoolsPage);
}
async attach(devtoolsPage) {
if (this.#attachedPages.has(devtoolsPage)) {
return;
}
this.#attachedPages.add(devtoolsPage);
try {
await devtoolsPage.exposeFunction('__onDevToolsCommentEvent', () => {
this.#handleCommentEvent();
});
}
catch (e) {
logger?.('DevToolsCommentBridge: exposeFunction already bound or failed', e);
}
try {
await devtoolsPage.evaluate(() => {
window.__onDevToolsCommentListener = () => {
window.__onDevToolsCommentEvent?.();
};
window.universe?.cd4aBridge?.addEventListener('CommentThreadsChanged', window.__onDevToolsCommentListener);
window.universe?.cd4aBridge?.setAgentAttached(true);
});
}
catch (e) {
logger?.('DevToolsCommentBridge: evaluate failed', e);
}
}
async getComments(devtoolsPage) {
return await devtoolsPage.evaluate(() => {
window.universe?.cd4aBridge?.setAgentAttached(true);
return window.universe?.cd4aBridge?.getCommentThreads() ?? [];
});
}
#handleCommentEvent() {
if (this.#commentDebounceTimer) {
clearTimeout(this.#commentDebounceTimer);
}
this.#commentDebounceTimer = setTimeout(() => {
this.#onNotification?.('DevTools comment threads updated');
}, this.#debounceMs);
}
dispose() {
if (this.#commentDebounceTimer) {
clearTimeout(this.#commentDebounceTimer);
this.#commentDebounceTimer = undefined;
}
for (const page of this.#attachedPages) {
try {
const result = page.evaluate(() => {
if (window.__onDevToolsCommentListener) {
window.universe?.cd4aBridge?.removeEventListener?.('CommentThreadsChanged', window.__onDevToolsCommentListener);
delete window.__onDevToolsCommentListener;
}
window.universe?.cd4aBridge?.setAgentAttached(false);
});
if (result && typeof result.catch === 'function') {
void result.catch(e => {
logger?.('DevToolsCommentBridge: failed to remove event listener', e);
});
}
}
catch (e) {
logger?.('DevToolsCommentBridge: failed to remove event listener', e);
}
}
this.#attachedPages.clear();
}
}
//# sourceMappingURL=DevToolsCommentBridge.js.map