@weavetab/mcp 2.5.0-beta.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/AGENTS.md +48 -0
- package/ARCHITECTURE.md +590 -0
- package/LICENSE +631 -0
- package/README.md +909 -0
- package/SECURITY.md +196 -0
- package/TROUBLESHOOTING.md +365 -0
- package/dist/anticaptcha/detector.d.ts +49 -0
- package/dist/anticaptcha/detector.js +465 -0
- package/dist/anticaptcha/integration.d.ts +36 -0
- package/dist/anticaptcha/integration.js +123 -0
- package/dist/anticaptcha/solver.d.ts +27 -0
- package/dist/anticaptcha/solver.js +552 -0
- package/dist/audit/logger.d.ts +13 -0
- package/dist/audit/logger.js +177 -0
- package/dist/audit/telemetry.d.ts +36 -0
- package/dist/audit/telemetry.js +162 -0
- package/dist/cdp/bridge.d.ts +16 -0
- package/dist/cdp/bridge.js +826 -0
- package/dist/cdp/confirm.d.ts +26 -0
- package/dist/cdp/confirm.js +79 -0
- package/dist/cdp/connector.d.ts +37 -0
- package/dist/cdp/connector.js +661 -0
- package/dist/cdp/extension.d.ts +36 -0
- package/dist/cdp/extension.js +118 -0
- package/dist/cdp/finder.d.ts +1 -0
- package/dist/cdp/finder.js +2 -0
- package/dist/cdp/helpers.d.ts +11 -0
- package/dist/cdp/helpers.js +195 -0
- package/dist/cdp/label_cache.d.ts +12 -0
- package/dist/cdp/label_cache.js +51 -0
- package/dist/cdp/lock.d.ts +33 -0
- package/dist/cdp/lock.js +206 -0
- package/dist/cdp/omni_broker.d.ts +17 -0
- package/dist/cdp/omni_broker.js +119 -0
- package/dist/cdp/profiles.d.ts +1 -0
- package/dist/cdp/profiles.js +87 -0
- package/dist/cdp/pruner.d.ts +41 -0
- package/dist/cdp/pruner.js +263 -0
- package/dist/cdp/ref_cache.d.ts +101 -0
- package/dist/cdp/ref_cache.js +234 -0
- package/dist/cdp/retry.d.ts +5 -0
- package/dist/cdp/retry.js +39 -0
- package/dist/cdp/retry_enhanced.d.ts +44 -0
- package/dist/cdp/retry_enhanced.js +102 -0
- package/dist/cdp/security.d.ts +50 -0
- package/dist/cdp/security.js +237 -0
- package/dist/cdp/verify.d.ts +39 -0
- package/dist/cdp/verify.js +143 -0
- package/dist/cdp/walker.d.ts +91 -0
- package/dist/cdp/walker.js +896 -0
- package/dist/cdp/walker.test.d.ts +2 -0
- package/dist/cdp/walker.test.js +172 -0
- package/dist/cdp/websocket_transport.d.ts +15 -0
- package/dist/cdp/websocket_transport.js +118 -0
- package/dist/cli/plugin.d.ts +9 -0
- package/dist/cli/plugin.js +1134 -0
- package/dist/cli/updater.d.ts +1 -0
- package/dist/cli/updater.js +72 -0
- package/dist/config/loader.d.ts +120 -0
- package/dist/config/loader.js +704 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1248 -0
- package/dist/intelligence/hints.d.ts +11 -0
- package/dist/intelligence/hints.js +39 -0
- package/dist/intelligence/intent.d.ts +33 -0
- package/dist/intelligence/intent.js +171 -0
- package/dist/intelligence/sessionMemory.d.ts +66 -0
- package/dist/intelligence/sessionMemory.js +284 -0
- package/dist/intelligence/sessionMemory.test.d.ts +2 -0
- package/dist/intelligence/sessionMemory.test.js +62 -0
- package/dist/intelligence/trail.d.ts +64 -0
- package/dist/intelligence/trail.js +233 -0
- package/dist/intelligence/trail.test.d.ts +2 -0
- package/dist/intelligence/trail.test.js +110 -0
- package/dist/intelligence/vision.d.ts +24 -0
- package/dist/intelligence/vision.js +151 -0
- package/dist/lifecycle/mission_manager.d.ts +16 -0
- package/dist/lifecycle/mission_manager.js +44 -0
- package/dist/overlay/bubble.d.ts +16 -0
- package/dist/overlay/bubble.js +37 -0
- package/dist/overlay/ghost.d.ts +35 -0
- package/dist/overlay/ghost.js +508 -0
- package/dist/overlay/injector.d.ts +22 -0
- package/dist/overlay/injector.js +198 -0
- package/dist/plugin/interface.d.ts +134 -0
- package/dist/plugin/interface.js +1 -0
- package/dist/plugin/loader.d.ts +18 -0
- package/dist/plugin/loader.js +155 -0
- package/dist/plugin/registry.d.ts +50 -0
- package/dist/plugin/registry.js +234 -0
- package/dist/security/blacklist.d.ts +24 -0
- package/dist/security/blacklist.js +80 -0
- package/dist/security/filter.d.ts +2 -0
- package/dist/security/filter.js +20 -0
- package/dist/security/guard.d.ts +8 -0
- package/dist/security/guard.js +35 -0
- package/dist/security/ratelimit.d.ts +11 -0
- package/dist/security/ratelimit.js +57 -0
- package/dist/security/secrets.d.ts +75 -0
- package/dist/security/secrets.js +365 -0
- package/dist/sensors/actionability.d.ts +81 -0
- package/dist/sensors/actionability.js +303 -0
- package/dist/sensors/guard.d.ts +25 -0
- package/dist/sensors/guard.js +168 -0
- package/dist/sensors/mutations.d.ts +23 -0
- package/dist/sensors/mutations.js +93 -0
- package/dist/sensors/network.d.ts +67 -0
- package/dist/sensors/network.js +193 -0
- package/dist/sensors/operation_monitor.d.ts +80 -0
- package/dist/sensors/operation_monitor.js +203 -0
- package/dist/sensors/pacing.d.ts +44 -0
- package/dist/sensors/pacing.js +111 -0
- package/dist/sensors/thoughts.d.ts +2 -0
- package/dist/sensors/thoughts.js +59 -0
- package/dist/sensors/wait.d.ts +12 -0
- package/dist/sensors/wait.js +44 -0
- package/dist/server.d.ts +7 -0
- package/dist/server.js +1687 -0
- package/dist/state/agent.d.ts +36 -0
- package/dist/state/agent.js +101 -0
- package/dist/state/cache.d.ts +16 -0
- package/dist/state/cache.js +92 -0
- package/dist/state/cache.test.d.ts +2 -0
- package/dist/state/cache.test.js +76 -0
- package/dist/state/delta.d.ts +71 -0
- package/dist/state/delta.js +234 -0
- package/dist/state/delta.test.d.ts +2 -0
- package/dist/state/delta.test.js +279 -0
- package/dist/state/groups.d.ts +15 -0
- package/dist/state/groups.js +80 -0
- package/dist/state/session.d.ts +30 -0
- package/dist/state/session.js +155 -0
- package/dist/tools/accessibility.d.ts +14 -0
- package/dist/tools/accessibility.js +32 -0
- package/dist/tools/ask.d.ts +14 -0
- package/dist/tools/ask.js +49 -0
- package/dist/tools/automation.d.ts +36 -0
- package/dist/tools/automation.js +218 -0
- package/dist/tools/browser_detect.d.ts +13 -0
- package/dist/tools/browser_detect.js +73 -0
- package/dist/tools/burst.d.ts +35 -0
- package/dist/tools/burst.js +344 -0
- package/dist/tools/canvas.d.ts +25 -0
- package/dist/tools/canvas.js +132 -0
- package/dist/tools/captcha.d.ts +38 -0
- package/dist/tools/captcha.js +209 -0
- package/dist/tools/click.d.ts +36 -0
- package/dist/tools/click.js +561 -0
- package/dist/tools/click_and_wait.d.ts +33 -0
- package/dist/tools/click_and_wait.js +149 -0
- package/dist/tools/clipboard.d.ts +29 -0
- package/dist/tools/clipboard.js +279 -0
- package/dist/tools/console.d.ts +21 -0
- package/dist/tools/console.js +107 -0
- package/dist/tools/cookies.d.ts +67 -0
- package/dist/tools/cookies.js +121 -0
- package/dist/tools/design_extract.d.ts +109 -0
- package/dist/tools/design_extract.js +641 -0
- package/dist/tools/dialog.d.ts +24 -0
- package/dist/tools/dialog.js +109 -0
- package/dist/tools/drag.d.ts +15 -0
- package/dist/tools/drag.js +29 -0
- package/dist/tools/emulation.d.ts +33 -0
- package/dist/tools/emulation.js +69 -0
- package/dist/tools/eval.d.ts +20 -0
- package/dist/tools/eval.js +92 -0
- package/dist/tools/fill.d.ts +41 -0
- package/dist/tools/fill.js +667 -0
- package/dist/tools/find.d.ts +30 -0
- package/dist/tools/find.js +60 -0
- package/dist/tools/geo.d.ts +19 -0
- package/dist/tools/geo.js +29 -0
- package/dist/tools/github/analyze.d.ts +4 -0
- package/dist/tools/github/analyze.js +113 -0
- package/dist/tools/github/cache.d.ts +21 -0
- package/dist/tools/github/cache.js +28 -0
- package/dist/tools/github/index.d.ts +4 -0
- package/dist/tools/github/index.js +4 -0
- package/dist/tools/github/issues.d.ts +9 -0
- package/dist/tools/github/issues.js +88 -0
- package/dist/tools/github/pr.d.ts +5 -0
- package/dist/tools/github/pr.js +88 -0
- package/dist/tools/github/rateLimiter.d.ts +4 -0
- package/dist/tools/github/rateLimiter.js +46 -0
- package/dist/tools/github/read.d.ts +34 -0
- package/dist/tools/github/read.js +74 -0
- package/dist/tools/github/repoContext.d.ts +20 -0
- package/dist/tools/github/repoContext.js +129 -0
- package/dist/tools/highlight.d.ts +20 -0
- package/dist/tools/highlight.js +140 -0
- package/dist/tools/hover.d.ts +19 -0
- package/dist/tools/hover.js +57 -0
- package/dist/tools/inspect.d.ts +17 -0
- package/dist/tools/inspect.js +125 -0
- package/dist/tools/integration.test.d.ts +2 -0
- package/dist/tools/integration.test.js +96 -0
- package/dist/tools/key.d.ts +25 -0
- package/dist/tools/key.js +173 -0
- package/dist/tools/macro_compiler.d.ts +7 -0
- package/dist/tools/macro_compiler.js +82 -0
- package/dist/tools/mouse.d.ts +21 -0
- package/dist/tools/mouse.js +62 -0
- package/dist/tools/navigate.d.ts +16 -0
- package/dist/tools/navigate.js +188 -0
- package/dist/tools/network_intercept.d.ts +17 -0
- package/dist/tools/network_intercept.js +151 -0
- package/dist/tools/office/index.d.ts +9 -0
- package/dist/tools/office/index.js +7 -0
- package/dist/tools/office/list.d.ts +15 -0
- package/dist/tools/office/list.js +41 -0
- package/dist/tools/office/parse.d.ts +20 -0
- package/dist/tools/office/parse.js +172 -0
- package/dist/tools/pdf.d.ts +22 -0
- package/dist/tools/pdf.js +42 -0
- package/dist/tools/performance.d.ts +12 -0
- package/dist/tools/performance.js +47 -0
- package/dist/tools/performance_test.d.ts +70 -0
- package/dist/tools/performance_test.js +128 -0
- package/dist/tools/plan.d.ts +39 -0
- package/dist/tools/plan.js +161 -0
- package/dist/tools/pointer.d.ts +35 -0
- package/dist/tools/pointer.js +522 -0
- package/dist/tools/read.d.ts +30 -0
- package/dist/tools/read.js +488 -0
- package/dist/tools/recording.d.ts +45 -0
- package/dist/tools/recording.js +124 -0
- package/dist/tools/response.d.ts +129 -0
- package/dist/tools/response.js +5 -0
- package/dist/tools/scrape.d.ts +24 -0
- package/dist/tools/scrape.js +140 -0
- package/dist/tools/screenshot.d.ts +40 -0
- package/dist/tools/screenshot.js +79 -0
- package/dist/tools/scroll.d.ts +23 -0
- package/dist/tools/scroll.js +196 -0
- package/dist/tools/select.d.ts +13 -0
- package/dist/tools/select.js +217 -0
- package/dist/tools/snapshot.d.ts +27 -0
- package/dist/tools/snapshot.js +99 -0
- package/dist/tools/storage.d.ts +18 -0
- package/dist/tools/storage.js +29 -0
- package/dist/tools/tabs.d.ts +77 -0
- package/dist/tools/tabs.js +342 -0
- package/dist/tools/thought.d.ts +16 -0
- package/dist/tools/thought.js +79 -0
- package/dist/tools/type.d.ts +65 -0
- package/dist/tools/type.js +1061 -0
- package/dist/tools/type_secret.d.ts +23 -0
- package/dist/tools/type_secret.js +229 -0
- package/dist/tools/upload.d.ts +19 -0
- package/dist/tools/upload.js +103 -0
- package/dist/tools/video_compiler.d.ts +24 -0
- package/dist/tools/video_compiler.js +199 -0
- package/dist/tools/viewport.d.ts +44 -0
- package/dist/tools/viewport.js +230 -0
- package/dist/tools/wait.d.ts +19 -0
- package/dist/tools/wait.js +202 -0
- package/dist/tools/wait_for.d.ts +23 -0
- package/dist/tools/wait_for.js +30 -0
- package/dist/tools/windows.d.ts +22 -0
- package/dist/tools/windows.js +57 -0
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +12 -0
- package/docs/DEV_MODE.md +68 -0
- package/docs/DOCUMENTATION.md +532 -0
- package/docs/PLUGINS.md +538 -0
- package/docs/TOOLS.md +104 -0
- package/docs/dev_plugin.md +310 -0
- package/ext-dist/background.js +467 -0
- package/ext-dist/content.js +3089 -0
- package/ext-dist/dashboard.html +583 -0
- package/ext-dist/hud/hud.js +73 -0
- package/ext-dist/hud/index.html +20 -0
- package/ext-dist/manifest.json +77 -0
- package/ext-dist/sidepanel/sidepanel.js +25 -0
- package/ext-dist/sidepanel.html +547 -0
- package/ext-dist/styles.css +218 -0
- package/icon.png +0 -0
- package/mcp.json +796 -0
- package/package.json +113 -0
- package/server.json +23 -0
- package/smithery.yaml +11 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
const browserAPI = typeof browser !== 'undefined' ? browser : chrome;
|
|
2
|
+
|
|
3
|
+
// Allow users to open the side panel by clicking on the action toolbar icon
|
|
4
|
+
if (browserAPI.sidePanel) {
|
|
5
|
+
browserAPI.sidePanel
|
|
6
|
+
.setPanelBehavior({ openPanelOnActionClick: true })
|
|
7
|
+
.catch((error) => console.error(error));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// ── Browser Startup: auto-open sidepanel ────────────────────────
|
|
11
|
+
// Clear minimized state on browser launch so sidepanel opens automatically
|
|
12
|
+
browserAPI.runtime.onStartup.addListener(function() {
|
|
13
|
+
try { browserAPI.storage.local.remove('wt_panel_minimized'); } catch(e) {}
|
|
14
|
+
});
|
|
15
|
+
// Also clear on install (first launch)
|
|
16
|
+
browserAPI.runtime.onInstalled.addListener(function() {
|
|
17
|
+
try { browserAPI.storage.local.remove('wt_panel_minimized'); } catch(e) {}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// HUD toggle command handler
|
|
21
|
+
browserAPI.commands.onCommand.addListener(function(command) {
|
|
22
|
+
if (command === 'toggle-hud') {
|
|
23
|
+
browserAPI.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
|
24
|
+
if (tabs[0] && tabs[0].id) {
|
|
25
|
+
browserAPI.tabs.sendMessage(tabs[0].id, { type: 'TOGGLE_HUD' }).catch(function(){});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (command === 'toggle-debug') {
|
|
30
|
+
browserAPI.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
|
31
|
+
if (tabs[0] && tabs[0].id) {
|
|
32
|
+
browserAPI.tabs.sendMessage(tabs[0].id, { type: 'TOGGLE_DEBUG' }).catch(function(){});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Runtime state
|
|
39
|
+
const controlledTabs = new Set();
|
|
40
|
+
const anchorTabs = new Set();
|
|
41
|
+
let currentGroupState = 'idle';
|
|
42
|
+
let activeSessionTabId = null;
|
|
43
|
+
|
|
44
|
+
// ── Sidepanel Open/Close Tracking ────────────────────────────────────────────
|
|
45
|
+
let isSidepanelOpen = false;
|
|
46
|
+
browserAPI.runtime.onConnect.addListener(function(port) {
|
|
47
|
+
if (port.name === 'wt-sidepanel') {
|
|
48
|
+
isSidepanelOpen = true;
|
|
49
|
+
// Notify all controlled tabs so HUD can suppress browser_thought pill
|
|
50
|
+
controlledTabs.forEach(tabId => {
|
|
51
|
+
browserAPI.tabs.sendMessage(tabId, { type: 'WT_SIDEPANEL_STATE', open: true }).catch(() => {});
|
|
52
|
+
});
|
|
53
|
+
port.onDisconnect.addListener(function() {
|
|
54
|
+
isSidepanelOpen = false;
|
|
55
|
+
controlledTabs.forEach(tabId => {
|
|
56
|
+
browserAPI.tabs.sendMessage(tabId, { type: 'WT_SIDEPANEL_STATE', open: false }).catch(() => {});
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// State color mapping — always blue, never yellow
|
|
63
|
+
const STATE_COLORS = {
|
|
64
|
+
idle: 'grey',
|
|
65
|
+
weaving: 'blue',
|
|
66
|
+
stuck: 'blue', // Keep blue, never yellow
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const STATE_BADGE = {
|
|
70
|
+
idle: { text: '', color: null },
|
|
71
|
+
weaving: { text: '\u25CF', color: '#3B82F6' },
|
|
72
|
+
stuck: { text: '\u25CF', color: '#3B82F6' }, // blue dot, not red
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
browserAPI.tabs.onCreated.addListener(async (tab) => {
|
|
77
|
+
if (!controlledTabs.has(tab.id)) return;
|
|
78
|
+
// Ungroup immediately — prevents Chrome from keeping this tab in any group
|
|
79
|
+
try { browserAPI.tabs.ungroup(tab.id).catch(() => {}); } catch(e) {}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
browserAPI.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
|
83
|
+
if (!controlledTabs.has(tabId)) return;
|
|
84
|
+
if (changeInfo.status === 'complete') {
|
|
85
|
+
// Ungroup on update to handle cases where Chrome re-groups after navigation
|
|
86
|
+
try { browserAPI.tabs.ungroup(tabId).catch(() => {}); } catch(e) {}
|
|
87
|
+
browserAPI.tabs.sendMessage(tabId, { type: 'Weavetab_GROUP_STATE', state: currentGroupState, isActive: tabId === activeSessionTabId }).catch(() => {});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
// Per-tab network interception using declarativeNetRequest
|
|
93
|
+
async function enableIntercept(tabId, pattern, mockStatus, mockBody) {
|
|
94
|
+
try {
|
|
95
|
+
await browserAPI.declarativeNetRequest.updateSessionRules({
|
|
96
|
+
addRules: [{
|
|
97
|
+
id: tabId,
|
|
98
|
+
priority: 1,
|
|
99
|
+
condition: { urlFilter: pattern, tabIds: [tabId] },
|
|
100
|
+
action: {
|
|
101
|
+
type: 'redirect',
|
|
102
|
+
redirect: {
|
|
103
|
+
url: `data:application/json,${encodeURIComponent(mockBody)}`
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}]
|
|
107
|
+
});
|
|
108
|
+
return { success: true };
|
|
109
|
+
} catch (e) {
|
|
110
|
+
console.error("Failed to enable intercept:", e);
|
|
111
|
+
return { success: false, error: e.message };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function disableIntercept(tabId) {
|
|
116
|
+
try {
|
|
117
|
+
await browserAPI.declarativeNetRequest.updateSessionRules({
|
|
118
|
+
removeRuleIds: [tabId]
|
|
119
|
+
});
|
|
120
|
+
return { success: true };
|
|
121
|
+
} catch (e) {
|
|
122
|
+
console.error("Failed to disable intercept:", e);
|
|
123
|
+
return { success: false, error: e.message };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Stale state guard: if no Weavetab_GROUP_STATE message for 90s, reset all controlled tabs to idle
|
|
128
|
+
let __wt_stateTimeout = null;
|
|
129
|
+
|
|
130
|
+
function resetToIdle() {
|
|
131
|
+
if (currentGroupState === 'idle') return;
|
|
132
|
+
currentGroupState = 'idle';
|
|
133
|
+
activeSessionTabId = null;
|
|
134
|
+
controlledTabs.forEach(tabId => {
|
|
135
|
+
browserAPI.tabs.sendMessage(tabId, { type: 'Weavetab_GROUP_STATE', state: 'idle', isActive: false }).catch(() => {});
|
|
136
|
+
});
|
|
137
|
+
if (browserAPI.action) {
|
|
138
|
+
browserAPI.action.setBadgeText({ text: '' }).catch(() => {});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function refreshStateTimeout() {
|
|
143
|
+
if (__wt_stateTimeout) clearTimeout(__wt_stateTimeout);
|
|
144
|
+
__wt_stateTimeout = setTimeout(resetToIdle, 120000); // 2 min stale guard
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Bridge: relay state from CLI (via CDP executeScript) to content scripts
|
|
148
|
+
// ── Sidepanel broadcast ─────────────────────────────────────────────────────
|
|
149
|
+
// Routes agent-activity messages (tool calls, thoughts, status) to the sidepanel
|
|
150
|
+
// so all visual state lives there, not in in-page overlays.
|
|
151
|
+
function broadcastToSidepanel(msg) {
|
|
152
|
+
browserAPI.runtime.sendMessage(msg).catch(() => {}); // sidepanel listens on runtime
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
browserAPI.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
156
|
+
// ── Forward tool call events to sidepanel ──
|
|
157
|
+
if (message.type === 'TOOL_CALL_EVENT') {
|
|
158
|
+
broadcastToSidepanel({ type: 'TOOL_CALL_EVENT', payload: message.payload });
|
|
159
|
+
}
|
|
160
|
+
// ── Smart thought routing ──
|
|
161
|
+
// browser_thought (kind='thought') → sidepanel when open, HUD when closed
|
|
162
|
+
// Scripted pill suppression is handled in the HUD via WT_SIDEPANEL_STATE
|
|
163
|
+
if (message.type === 'WT_THOUGHT') {
|
|
164
|
+
if (isSidepanelOpen) {
|
|
165
|
+
// Route to sidepanel only — suppress HUD rendering
|
|
166
|
+
broadcastToSidepanel({ type: 'WT_THOUGHT', text: message.text, kind: message.kind });
|
|
167
|
+
// Tell the HUD iframe in the active tab to suppress the browser_thought pill
|
|
168
|
+
if (sender.tab && sender.tab.id) {
|
|
169
|
+
browserAPI.tabs.sendMessage(sender.tab.id, { type: 'WT_SUPPRESS_THOUGHT_HUD' }).catch(() => {});
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
// Sidepanel closed — let the HUD handle it normally via the iframe relay
|
|
173
|
+
broadcastToSidepanel({ type: 'WT_THOUGHT', text: message.text, kind: message.kind });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── User messaging ──
|
|
178
|
+
if (message.type === 'WT_USER_NOTE') {
|
|
179
|
+
const payload = {
|
|
180
|
+
type: 'WT_USER_NOTE_INJECT',
|
|
181
|
+
text: message.text,
|
|
182
|
+
snipe: message.snipe
|
|
183
|
+
};
|
|
184
|
+
// Query active tab in current window and send message immediately
|
|
185
|
+
browserAPI.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
|
186
|
+
if (tabs[0] && tabs[0].id) {
|
|
187
|
+
browserAPI.tabs.sendMessage(tabs[0].id, payload).catch(function(){});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
// Send to activeSessionTabId if set
|
|
191
|
+
if (activeSessionTabId) {
|
|
192
|
+
browserAPI.tabs.sendMessage(activeSessionTabId, payload).catch(function(){});
|
|
193
|
+
}
|
|
194
|
+
// Fallback to all controlled tabs
|
|
195
|
+
controlledTabs.forEach(tabId => {
|
|
196
|
+
browserAPI.tabs.sendMessage(tabId, payload).catch(function(){});
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (message.type === 'WT_TOGGLE_MASTER_VISUALS') {
|
|
201
|
+
browserAPI.storage.local.set({ wt_master_visuals: message.enabled }).catch(() => {});
|
|
202
|
+
controlledTabs.forEach(tabId => {
|
|
203
|
+
browserAPI.tabs.sendMessage(tabId, { type: 'WT_TOGGLE_MASTER_VISUALS', enabled: message.enabled }).catch(() => {});
|
|
204
|
+
});
|
|
205
|
+
sendResponse({ ok: true });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (message.type === 'Weavetab_STATE') {
|
|
209
|
+
broadcastToSidepanel(message);
|
|
210
|
+
controlledTabs.forEach(tabId => {
|
|
211
|
+
browserAPI.tabs.sendMessage(tabId, message).catch(() => {});
|
|
212
|
+
});
|
|
213
|
+
sendResponse({ ok: true });
|
|
214
|
+
}
|
|
215
|
+
if (message.type === 'Weavetab_CONFIG') {
|
|
216
|
+
const { groupTabs } = message;
|
|
217
|
+
browserAPI.storage.local.set({
|
|
218
|
+
weaveGroupEnabled: groupTabs !== false,
|
|
219
|
+
}).catch(() => {});
|
|
220
|
+
sendResponse({ ok: true });
|
|
221
|
+
}
|
|
222
|
+
if (message.type === 'Weavetab_GROUP_STATE') {
|
|
223
|
+
const { state, word } = message;
|
|
224
|
+
currentGroupState = state;
|
|
225
|
+
refreshStateTimeout();
|
|
226
|
+
const color = STATE_COLORS[state] || 'blue';
|
|
227
|
+
const badge = STATE_BADGE[state] || STATE_BADGE.idle;
|
|
228
|
+
|
|
229
|
+
// Track which tab relayed this state update (the active session tab)
|
|
230
|
+
if (sender.tab) activeSessionTabId = sender.tab.id;
|
|
231
|
+
// Per-tab badge
|
|
232
|
+
if (browserAPI.action) {
|
|
233
|
+
const ids = Array.from(controlledTabs);
|
|
234
|
+
ids.forEach(tid => {
|
|
235
|
+
if (badge.text) {
|
|
236
|
+
browserAPI.action.setBadgeText({ tabId: tid, text: badge.text }).catch(() => {});
|
|
237
|
+
if (badge.color) {
|
|
238
|
+
browserAPI.action.setBadgeBackgroundColor({ tabId: tid, color: badge.color }).catch(() => {});
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
browserAPI.action.setBadgeText({ tabId: tid, text: '' }).catch(() => {});
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Broadcast state to all controlled tabs so they update their favicons
|
|
247
|
+
controlledTabs.forEach(tabId => {
|
|
248
|
+
browserAPI.tabs.sendMessage(tabId, { type: 'Weavetab_GROUP_STATE', state, isActive: tabId === activeSessionTabId }).catch(() => {});
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// ── Mirror to sidepanel status dot ──
|
|
252
|
+
broadcastToSidepanel({ type: 'WT_AGENT_STATUS', status: state });
|
|
253
|
+
|
|
254
|
+
sendResponse({ ok: true });
|
|
255
|
+
}
|
|
256
|
+
if (message.type === 'REGISTER_TAB') {
|
|
257
|
+
// Skip about:blank and chrome:// pages
|
|
258
|
+
if (sender.tab.url === 'about:blank' || sender.tab.url.startsWith('chrome://')) {
|
|
259
|
+
sendResponse({ ok: true, skipped: true });
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
controlledTabs.add(sender.tab.id);
|
|
263
|
+
refreshStateTimeout();
|
|
264
|
+
|
|
265
|
+
// Immediately inform the tab of the current group state so it can set its favicon
|
|
266
|
+
browserAPI.tabs.sendMessage(sender.tab.id, { type: 'Weavetab_GROUP_STATE', state: currentGroupState, isActive: sender.tab.id === activeSessionTabId }).catch(() => {});
|
|
267
|
+
|
|
268
|
+
updateBadge();
|
|
269
|
+
sendResponse({ ok: true });
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (message.type === 'NETWORK_INTERCEPT_ENABLE') {
|
|
273
|
+
enableIntercept(sender.tab.id, message.pattern, message.mockStatus, message.mockBody)
|
|
274
|
+
.then(res => sendResponse(res));
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
if (message.type === 'NETWORK_INTERCEPT_DISABLE') {
|
|
278
|
+
disableIntercept(sender.tab.id)
|
|
279
|
+
.then(res => sendResponse(res));
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
if (message.type === 'GET_ANCHOR_STATUS') {
|
|
283
|
+
sendResponse({ isAnchor: anchorTabs.has(sender.tab.id) });
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
if (message.type === 'SET_ANCHOR_TAB') {
|
|
287
|
+
if (message.anchor) anchorTabs.add(sender.tab.id);
|
|
288
|
+
else anchorTabs.delete(sender.tab.id);
|
|
289
|
+
sendResponse({ ok: true });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ── User feedback relay: sidepanel / content script → storage queue ────────
|
|
293
|
+
// CDP polls window.__Weavetab.popUserFeedback() or window.__wt_chat_queue which reads from this queue.
|
|
294
|
+
if (message.type === 'USER_FEEDBACK' || message.type === 'WT_USER_NOTE') {
|
|
295
|
+
if (message.text || message.snipe) {
|
|
296
|
+
const noteEntry = {
|
|
297
|
+
text: message.text || '',
|
|
298
|
+
snipe: message.snipe || null,
|
|
299
|
+
ts: message.ts || Date.now(),
|
|
300
|
+
tabId: sender.tab && sender.tab.id
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
browserAPI.storage.local.get('__wt_feedback_queue', function(res) {
|
|
304
|
+
const queue = res['__wt_feedback_queue'] || [];
|
|
305
|
+
queue.push(noteEntry);
|
|
306
|
+
// Cap queue at 20 entries
|
|
307
|
+
if (queue.length > 20) queue.splice(0, queue.length - 20);
|
|
308
|
+
browserAPI.storage.local.set({ '__wt_feedback_queue': queue });
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Forward directly to active session tab content script for immediate DOM queue push & interrupt
|
|
312
|
+
browserAPI.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
|
313
|
+
if (tabs[0]?.id) {
|
|
314
|
+
browserAPI.tabs.sendMessage(tabs[0].id, {
|
|
315
|
+
type: 'WT_SNIPE_INJECT',
|
|
316
|
+
entry: noteEntry
|
|
317
|
+
}).catch(() => {});
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
sendResponse({ ok: true });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
// Alert tab: mark tabs with alert dialogs waiting + write to storage so CDP can see it
|
|
326
|
+
if (message.type === 'TAB_ALERT_WAITING') {
|
|
327
|
+
const alertTabId = sender.tab && sender.tab.id;
|
|
328
|
+
if (alertTabId) {
|
|
329
|
+
browserAPI.tabs.sendMessage(alertTabId, { type: 'Weavetab_GROUP_STATE', state: 'weaving', isActive: false }).catch(() => {});
|
|
330
|
+
// Write alert state to storage — CDP polls __Weavetab.getAlertState()
|
|
331
|
+
browserAPI.storage.local.set({ '__wt_alert_state': { pending: true, tabId: alertTabId, ts: Date.now() } });
|
|
332
|
+
}
|
|
333
|
+
sendResponse({ ok: true });
|
|
334
|
+
}
|
|
335
|
+
if (message.type === 'TAB_ALERT_CLEARED') {
|
|
336
|
+
const alertTabId = sender.tab && sender.tab.id;
|
|
337
|
+
if (alertTabId) {
|
|
338
|
+
browserAPI.tabs.sendMessage(alertTabId, { type: 'Weavetab_GROUP_STATE', state: 'idle', isActive: false }).catch(() => {});
|
|
339
|
+
browserAPI.storage.local.set({ '__wt_alert_state': { pending: false, tabId: alertTabId, ts: Date.now() } });
|
|
340
|
+
}
|
|
341
|
+
sendResponse({ ok: true });
|
|
342
|
+
}
|
|
343
|
+
if (message.type === 'RELOAD_EXTENSION') {
|
|
344
|
+
sendResponse({ ok: true });
|
|
345
|
+
browserAPI.runtime.reload();
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
browserAPI.tabs.onRemoved.addListener((tabId) => {
|
|
352
|
+
if (controlledTabs.has(tabId)) {
|
|
353
|
+
controlledTabs.delete(tabId);
|
|
354
|
+
updateBadge();
|
|
355
|
+
}
|
|
356
|
+
anchorTabs.delete(tabId);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
// Startup cleanup: Ungroup all Weavetab tabs and clear badges
|
|
361
|
+
browserAPI.runtime.onInstalled.addListener(() => {
|
|
362
|
+
browserAPI.tabs.query({}, (tabs) => {
|
|
363
|
+
const ids = tabs.map(t => t.id).filter(id => id !== undefined);
|
|
364
|
+
if (ids.length > 0) {
|
|
365
|
+
browserAPI.tabs.ungroup(ids).catch(() => {});
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
function updateBadge() {
|
|
371
|
+
if (!browserAPI.action) return;
|
|
372
|
+
const ids = Array.from(controlledTabs);
|
|
373
|
+
if (ids.length === 0) {
|
|
374
|
+
browserAPI.action.setBadgeText({ text: '' }).catch(() => {});
|
|
375
|
+
} else {
|
|
376
|
+
ids.forEach(tid => {
|
|
377
|
+
// Just set the dot, but don't group
|
|
378
|
+
browserAPI.action.setBadgeText({ tabId: tid, text: '\u25CF' }).catch(() => {});
|
|
379
|
+
browserAPI.action.setBadgeBackgroundColor({ tabId: tid, color: '#3B82F6' }).catch(() => {});
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// On startup: close stale blank tabs — but NEVER the last remaining tab.
|
|
385
|
+
// Weavetab launches Chrome on about:blank, so removing the only tab closes
|
|
386
|
+
// the browser window (graceful shutdown ~1s after launch → ECONNREFUSED loop).
|
|
387
|
+
browserAPI.runtime.onStartup.addListener(async () => {
|
|
388
|
+
try {
|
|
389
|
+
const blanks = await browserAPI.tabs.query({ url: 'about:blank' });
|
|
390
|
+
if (blanks.length === 0) return;
|
|
391
|
+
const all = await browserAPI.tabs.query({});
|
|
392
|
+
// Keep one tab alive if every tab would otherwise be closed.
|
|
393
|
+
const mustKeep = blanks.length === all.length ? 1 : 0;
|
|
394
|
+
blanks.slice(0, blanks.length - mustKeep).forEach(t =>
|
|
395
|
+
browserAPI.tabs.remove(t.id).catch(() => {})
|
|
396
|
+
);
|
|
397
|
+
} catch (e) {
|
|
398
|
+
// Non-fatal: never let tab cleanup crash the service worker or close the browser.
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// Network blocking for speed (delayed to avoid 'No SW' on cold start)
|
|
403
|
+
// Guard: only run if the service worker is still alive (not being terminated)
|
|
404
|
+
setTimeout(function() {
|
|
405
|
+
// Check the runtime is still valid before calling declarativeNetRequest
|
|
406
|
+
try {
|
|
407
|
+
if (!browserAPI.runtime || !browserAPI.runtime.id) return;
|
|
408
|
+
browserAPI.declarativeNetRequest.updateDynamicRules({
|
|
409
|
+
removeRuleIds: [1, 2, 3, 4],
|
|
410
|
+
addRules: [
|
|
411
|
+
{ id: 1, priority: 1, action: { type: 'block' }, condition: { urlFilter: '*google-analytics.com*', resourceTypes: ['script', 'xmlhttprequest', 'ping'] } },
|
|
412
|
+
{ id: 2, priority: 1, action: { type: 'block' }, condition: { urlFilter: '*doubleclick.net*', resourceTypes: ['script', 'xmlhttprequest', 'ping', 'image', 'sub_frame'] } },
|
|
413
|
+
{ id: 3, priority: 1, action: { type: 'block' }, condition: { urlFilter: '*facebook.net/en_US/fbevents.js*', resourceTypes: ['script'] } }
|
|
414
|
+
// NOTE: GTM blocking removed — some sites bundle critical resources through GTM
|
|
415
|
+
]
|
|
416
|
+
}).catch(function(e) {
|
|
417
|
+
// Non-fatal — log for debugging only
|
|
418
|
+
console.warn('[Weavetab] Dynamic rules update failed (non-fatal):', e && e.message);
|
|
419
|
+
});
|
|
420
|
+
} catch(e) {
|
|
421
|
+
// Service worker terminated or runtime invalidated — safe to ignore
|
|
422
|
+
}
|
|
423
|
+
}, 1000);
|
|
424
|
+
|
|
425
|
+
// ─── Omnibox: Weavetab:// protocol via browserAPI.omnibox ─────────────────────
|
|
426
|
+
|
|
427
|
+
const DASHBOARD_URL = browserAPI.runtime.getURL('dashboard.html');
|
|
428
|
+
|
|
429
|
+
browserAPI.omnibox.onInputStarted.addListener(() => {
|
|
430
|
+
browserAPI.omnibox.setDefaultSuggestion({
|
|
431
|
+
description: 'Open Weavetab Dashboard <url>chrome-extension://...</url>'
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
browserAPI.omnibox.onInputChanged.addListener((text, suggest) => {
|
|
436
|
+
const suggestions = [];
|
|
437
|
+
const lower = text.toLowerCase();
|
|
438
|
+
if (!lower || lower === 'dashboard' || 'dashboard'.startsWith(lower)) {
|
|
439
|
+
suggestions.push({
|
|
440
|
+
content: 'dashboard',
|
|
441
|
+
description: 'Open Weavetab Dashboard'
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
if ('help'.startsWith(lower)) {
|
|
445
|
+
suggestions.push({
|
|
446
|
+
content: 'help',
|
|
447
|
+
description: 'Weavetab Help & Documentation'
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
suggest(suggestions);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
browserAPI.omnibox.onInputEntered.addListener((text, disposition) => {
|
|
454
|
+
const branch = text && text !== 'dashboard' ? encodeURIComponent(text) : 'default';
|
|
455
|
+
const url = DASHBOARD_URL + `?branch=${branch}`;
|
|
456
|
+
switch (disposition) {
|
|
457
|
+
case 'currentTab':
|
|
458
|
+
browserAPI.tabs.update({ url });
|
|
459
|
+
break;
|
|
460
|
+
case 'newForegroundTab':
|
|
461
|
+
browserAPI.tabs.create({ url });
|
|
462
|
+
break;
|
|
463
|
+
case 'newBackgroundTab':
|
|
464
|
+
browserAPI.tabs.create({ url, active: false });
|
|
465
|
+
break;
|
|
466
|
+
}
|
|
467
|
+
});
|