@weavetab/mcp 2.5.0-beta.1 → 2.5.0-beta.4

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.
Files changed (156) hide show
  1. package/AGENTS.md +2 -1
  2. package/ARCHITECTURE.md +6 -6
  3. package/LICENSE +1 -1
  4. package/README.md +164 -802
  5. package/SECURITY.md +33 -22
  6. package/TROUBLESHOOTING.md +3 -3
  7. package/dist/cdp/bridge.d.ts +10 -0
  8. package/dist/cdp/bridge.js +285 -78
  9. package/dist/cdp/connector.d.ts +7 -3
  10. package/dist/cdp/connector.js +196 -75
  11. package/dist/cdp/helpers.d.ts +4 -0
  12. package/dist/cdp/helpers.js +181 -0
  13. package/dist/cdp/lock.d.ts +9 -6
  14. package/dist/cdp/lock.js +72 -59
  15. package/dist/cdp/omni_broker.d.ts +2 -1
  16. package/dist/cdp/omni_broker.js +13 -7
  17. package/dist/cdp/profiles.d.ts +10 -0
  18. package/dist/cdp/profiles.js +65 -0
  19. package/dist/cdp/walker.d.ts +25 -1
  20. package/dist/cdp/walker.js +354 -7
  21. package/dist/cli/plugin.d.ts +0 -2
  22. package/dist/cli/plugin.js +51 -696
  23. package/dist/cli/updater.d.ts +1 -1
  24. package/dist/cli/updater.js +27 -7
  25. package/dist/config/loader.d.ts +33 -6
  26. package/dist/config/loader.js +174 -22
  27. package/dist/desktop/discovery.d.ts +44 -0
  28. package/dist/desktop/discovery.js +364 -0
  29. package/dist/index.js +140 -64
  30. package/dist/intelligence/marks.d.ts +36 -0
  31. package/dist/intelligence/marks.js +30 -0
  32. package/dist/intelligence/patternCompiler.d.ts +118 -0
  33. package/dist/intelligence/patternCompiler.js +259 -0
  34. package/dist/intelligence/sessionMemory.d.ts +2 -0
  35. package/dist/intelligence/sessionMemory.js +18 -8
  36. package/dist/overlay/ghost.js +2 -2
  37. package/dist/overlay/injector.js +3 -5
  38. package/dist/plugin/extension_bridge.d.ts +40 -0
  39. package/dist/plugin/extension_bridge.js +158 -0
  40. package/dist/plugin/interface.d.ts +151 -15
  41. package/dist/plugin/loader.d.ts +19 -1
  42. package/dist/plugin/loader.js +331 -63
  43. package/dist/plugin/pipeline.d.ts +75 -0
  44. package/dist/plugin/pipeline.js +183 -0
  45. package/dist/plugin/registry.js +12 -1
  46. package/dist/plugin/storage.d.ts +51 -0
  47. package/dist/plugin/storage.js +164 -0
  48. package/dist/security/secrets.d.ts +1 -0
  49. package/dist/security/secrets.js +13 -0
  50. package/dist/sensors/actionability.js +1 -2
  51. package/dist/sensors/guard.js +4 -10
  52. package/dist/sensors/mutations.js +12 -0
  53. package/dist/sensors/operation_monitor.js +1 -0
  54. package/dist/server.d.ts +1 -1
  55. package/dist/server.js +600 -236
  56. package/dist/state/agent.d.ts +1 -0
  57. package/dist/state/agent.js +3 -0
  58. package/dist/state/delta.d.ts +12 -4
  59. package/dist/state/delta.js +67 -14
  60. package/dist/state/session.d.ts +8 -2
  61. package/dist/state/session.js +60 -13
  62. package/dist/tools/browser_detect.d.ts +16 -2
  63. package/dist/tools/browser_detect.js +54 -6
  64. package/dist/tools/burst.d.ts +17 -7
  65. package/dist/tools/burst.js +240 -83
  66. package/dist/tools/checkpoint.d.ts +38 -0
  67. package/dist/tools/checkpoint.js +271 -0
  68. package/dist/tools/click.d.ts +1 -0
  69. package/dist/tools/click.js +97 -98
  70. package/dist/tools/clipboard.js +31 -24
  71. package/dist/tools/design_extract.js +1 -1
  72. package/dist/tools/eval.js +1 -1
  73. package/dist/tools/fill.d.ts +20 -1
  74. package/dist/tools/fill.js +199 -40
  75. package/dist/tools/find.d.ts +16 -0
  76. package/dist/tools/find.js +67 -44
  77. package/dist/tools/github/index.d.ts +19 -4
  78. package/dist/tools/github/index.js +40 -4
  79. package/dist/tools/highlight.d.ts +6 -2
  80. package/dist/tools/highlight.js +158 -72
  81. package/dist/tools/inspect.js +1 -1
  82. package/dist/tools/key.js +65 -56
  83. package/dist/tools/navigate.d.ts +1 -1
  84. package/dist/tools/navigate.js +57 -44
  85. package/dist/tools/pdf.js +21 -13
  86. package/dist/tools/pointer.d.ts +18 -3
  87. package/dist/tools/pointer.js +89 -1
  88. package/dist/tools/read.d.ts +28 -8
  89. package/dist/tools/read.js +230 -56
  90. package/dist/tools/scrape.js +67 -13
  91. package/dist/tools/screenshot.js +21 -16
  92. package/dist/tools/scroll.js +6 -11
  93. package/dist/tools/select.js +8 -2
  94. package/dist/tools/snapshot.js +3 -34
  95. package/dist/tools/tabs.d.ts +10 -10
  96. package/dist/tools/tabs.js +55 -39
  97. package/dist/tools/thought.d.ts +2 -0
  98. package/dist/tools/thought.js +13 -14
  99. package/dist/tools/type.d.ts +2 -0
  100. package/dist/tools/type.js +109 -60
  101. package/dist/tools/type_secret.js +42 -76
  102. package/dist/tools/upload.js +1 -1
  103. package/dist/tools/video_compiler.d.ts +1 -1
  104. package/dist/tools/video_compiler.js +11 -12
  105. package/dist/version.d.ts +5 -0
  106. package/dist/version.js +5 -0
  107. package/docs/DOCUMENTATION.md +82 -36
  108. package/docs/PLUGINS.md +82 -499
  109. package/docs/TOOLS.md +51 -99
  110. package/docs/architecture/blind-injection.md +83 -0
  111. package/docs/architecture/dual-injection.md +32 -0
  112. package/docs/architecture/overview.md +49 -0
  113. package/docs/architecture/security.md +35 -0
  114. package/docs/architecture/transport.md +37 -0
  115. package/docs/captcha-stealth/captcha-solver.md +75 -0
  116. package/docs/captcha-stealth/stealth-physics.md +60 -0
  117. package/docs/cli/cli-commands.md +44 -0
  118. package/docs/cli/cli-flags.md +20 -0
  119. package/docs/cli/cli-introduction.md +20 -0
  120. package/docs/cli/cli-scripting.md +32 -0
  121. package/docs/cli/g-ide/ide-antigravity.md +24 -0
  122. package/docs/cli/g-ide/ide-claude-code.md +24 -0
  123. package/docs/cli/g-ide/ide-claude-desktop.md +32 -0
  124. package/docs/cli/g-ide/ide-cursor.md +31 -0
  125. package/docs/cli/g-ide/ide-generic.md +34 -0
  126. package/docs/cli/g-ide/ide-opencode.md +24 -0
  127. package/docs/cli/g-ide/ide-vscode-copilot.md +24 -0
  128. package/docs/cli/g-ide/ide-windsurf.md +24 -0
  129. package/docs/configuration/config-locations.md +24 -0
  130. package/docs/configuration/configuration.md +73 -0
  131. package/docs/configuration/env-variables.md +19 -0
  132. package/docs/configuration/folders.md +55 -0
  133. package/docs/desktop-automation/electron-apps.md +217 -0
  134. package/docs/get-started/installation.md +47 -0
  135. package/docs/get-started/introduction.md +60 -0
  136. package/docs/get-started/quickstart.md +54 -0
  137. package/docs/get-started/setup-wizard.md +26 -0
  138. package/docs/intelligence/site-profiles.md +151 -0
  139. package/docs/skills-ecosystem/skills-overview.md +35 -0
  140. package/docs/skills-ecosystem/skills-recipes.md +36 -0
  141. package/docs/tools/tools.md +631 -0
  142. package/docs/troubleshooting/trouble-browser.md +27 -0
  143. package/docs/troubleshooting/trouble-config.md +20 -0
  144. package/docs/troubleshooting/trouble-loop.md +31 -0
  145. package/ext-dist/background.js +10 -62
  146. package/ext-dist/content.js +333 -921
  147. package/ext-dist/hud/hud.js +9 -9
  148. package/ext-dist/manifest.json +2 -6
  149. package/ext-dist/styles.css +6 -1
  150. package/mcp.json +108 -72
  151. package/package.json +14 -9
  152. package/server.json +3 -3
  153. package/docs/DEV_MODE.md +0 -68
  154. package/docs/dev_plugin.md +0 -310
  155. package/ext-dist/sidepanel/sidepanel.js +0 -25
  156. package/ext-dist/sidepanel.html +0 -547
@@ -1,7 +1,7 @@
1
1
  import fs from "fs/promises";
2
2
  import path from "path";
3
3
  import { getOutputDir, getConfigAgentId } from "../config/loader.js";
4
- import { hideWeaveTabOverlay, restoreWeaveTabOverlay } from "../cdp/helpers.js";
4
+ import { hideWeaveTabOverlay, restoreWeaveTabOverlay, maskSecretFieldsForCapture, restoreSecretFieldsAfterCapture } from "../cdp/helpers.js";
5
5
  import { clearTabCache } from "../state/cache.js";
6
6
  import { clearSnapshot } from "../state/delta.js";
7
7
  import { sessionRegistry } from "../state/session.js";
@@ -28,22 +28,7 @@ export async function browserSnapshot(session, options, config) {
28
28
  }
29
29
  // ── Blank secret field values before capture ──────────────────────────
30
30
  // Prevents credential values from being embedded in the MHTML archive.
31
- // data-wt-secret is set by browser_type_secret at injection time.
32
- await session.Runtime.evaluate({
33
- expression: `(function() {
34
- var els = document.querySelectorAll('[data-wt-secret], input[type="password"]');
35
- for (var i = 0; i < els.length; i++) {
36
- var el = els[i];
37
- el.__wt_snap_backup = el.value;
38
- try { el.value = ''; } catch(e) {}
39
- if (el.isContentEditable) {
40
- el.__wt_snap_text_backup = el.textContent;
41
- try { el.textContent = ''; } catch(e) {}
42
- }
43
- }
44
- })()`,
45
- returnByValue: false,
46
- }).catch(() => { });
31
+ await maskSecretFieldsForCapture(session);
47
32
  let snapshotData;
48
33
  try {
49
34
  const res = await session.Page.captureSnapshot({ format: "mhtml" });
@@ -51,26 +36,10 @@ export async function browserSnapshot(session, options, config) {
51
36
  }
52
37
  finally {
53
38
  // ── Restore secret field values after capture (always runs) ──────────
39
+ await restoreSecretFieldsAfterCapture(session);
54
40
  if (shouldHide) {
55
41
  await restoreWeaveTabOverlay(session);
56
42
  }
57
- await session.Runtime.evaluate({
58
- expression: `(function() {
59
- var els = document.querySelectorAll('[data-wt-secret], input[type="password"]');
60
- for (var i = 0; i < els.length; i++) {
61
- var el = els[i];
62
- if (el.__wt_snap_backup !== undefined) {
63
- try { el.value = el.__wt_snap_backup; } catch(e) {}
64
- delete el.__wt_snap_backup;
65
- }
66
- if (el.__wt_snap_text_backup !== undefined) {
67
- try { el.textContent = el.__wt_snap_text_backup; } catch(e) {}
68
- delete el.__wt_snap_text_backup;
69
- }
70
- }
71
- })()`,
72
- returnByValue: false,
73
- }).catch(() => { });
74
43
  }
75
44
  await fs.mkdir(path.dirname(filePath), { recursive: true });
76
45
  await fs.writeFile(filePath, snapshotData, "utf8");
@@ -2,7 +2,7 @@ import type { Config } from "../config/loader.js";
2
2
  export declare function recordTabActivity(targetId: string): void;
3
3
  export declare function lockTab(targetId: string): void;
4
4
  export declare function unlockTab(targetId: string): void;
5
- export declare function evaluateTabSemantics(targetId: string): Promise<void>;
5
+ export declare function evaluateTabSemantics(targetId: string, appName?: string): Promise<void>;
6
6
  export interface TabInfo {
7
7
  id: string;
8
8
  title: string;
@@ -11,30 +11,30 @@ export interface TabInfo {
11
11
  health: "alive" | "dead" | "unreachable";
12
12
  score: number;
13
13
  }
14
- export declare function WeavetabOpen(url: string, config: Config, reuse?: boolean): Promise<{
14
+ export declare function WeavetabOpen(url: string, config: Config, reuse?: boolean, appName?: string): Promise<{
15
15
  success: true;
16
16
  tabId: string;
17
17
  url: string;
18
18
  reused?: boolean;
19
19
  }>;
20
- export declare function WeavetabSwitch(tabId: string, config: Config): Promise<{
20
+ export declare function WeavetabSwitch(tabId: string, config: Config, appName?: string): Promise<{
21
21
  success: true;
22
22
  tab_id: string;
23
23
  title: string;
24
24
  url: string;
25
25
  contextSwitchCostMs: number;
26
26
  }>;
27
- export declare function WeavetabList(config: Config): Promise<{
27
+ export declare function WeavetabList(config: Config, appName?: string): Promise<{
28
28
  tabs: TabInfo[];
29
29
  }>;
30
- export declare function WeavetabClose(tabId: string, config: Config, force?: boolean): Promise<{
30
+ export declare function WeavetabClose(tabId: string, config: Config, force?: boolean, appName?: string): Promise<{
31
31
  success: true;
32
32
  tab_id: string;
33
33
  }>;
34
34
  /**
35
35
  * Batch close multiple tabs at once — saves multiple round-trips.
36
36
  */
37
- export declare function WeavetabCloseBatch(tabIds: string[], config: Config, force?: boolean): Promise<{
37
+ export declare function WeavetabCloseBatch(tabIds: string[], config: Config, force?: boolean, appName?: string): Promise<{
38
38
  success: true;
39
39
  closed: string[];
40
40
  skipped: string[];
@@ -42,7 +42,7 @@ export declare function WeavetabCloseBatch(tabIds: string[], config: Config, for
42
42
  /**
43
43
  * Consolidate: deduplicate tabs by URL, close duplicates.
44
44
  */
45
- export declare function WeavetabConsolidate(config: Config): Promise<{
45
+ export declare function WeavetabConsolidate(config: Config, appName?: string): Promise<{
46
46
  success: true;
47
47
  tabs_before: number;
48
48
  tabs_after: number;
@@ -51,7 +51,7 @@ export declare function WeavetabConsolidate(config: Config): Promise<{
51
51
  /**
52
52
  * Heal: check all tabs for crashed state and reload them.
53
53
  */
54
- export declare function WeavetabHeal(config: Config): Promise<{
54
+ export declare function WeavetabHeal(config: Config, appName?: string): Promise<{
55
55
  success: true;
56
56
  healed: number;
57
57
  tabs_checked: number;
@@ -68,10 +68,10 @@ export interface WindowInfo {
68
68
  };
69
69
  focused: boolean;
70
70
  }
71
- export declare function weaveWindowList(config: Config): Promise<{
71
+ export declare function weaveWindowList(config: Config, appName?: string): Promise<{
72
72
  windows: WindowInfo[];
73
73
  }>;
74
- export declare function weaveFocusWindow(windowId: number, config: Config): Promise<{
74
+ export declare function weaveFocusWindow(windowId: number, config: Config, appName?: string): Promise<{
75
75
  success: true;
76
76
  windowId: number;
77
77
  }>;
@@ -8,7 +8,13 @@ import { readLock } from "../cdp/lock.js";
8
8
  import { resetLoopCounter } from "../intelligence/trail.js";
9
9
  import { getConfigAgentId, getConfigMaxTabs } from "../config/loader.js";
10
10
  /** Resolve the active CDP port — live > lock file */
11
- function resolvePort(_config) {
11
+ function resolvePort(_config, appName) {
12
+ if (appName) {
13
+ const lock = readLock(appName);
14
+ if (lock && lock.port)
15
+ return lock.port;
16
+ throw new Error(`[!] No active session for Electron app "${appName}". Launch it first.`);
17
+ }
12
18
  const port = getPort() || readLock()?.port;
13
19
  if (!port)
14
20
  throw new Error("[!] No active browser session. Run browser_go first.");
@@ -44,9 +50,9 @@ function calculateSemanticScore(url, title) {
44
50
  score += 30;
45
51
  return Math.min(score, 100);
46
52
  }
47
- export async function evaluateTabSemantics(targetId) {
53
+ export async function evaluateTabSemantics(targetId, appName) {
48
54
  try {
49
- const client = await connectToTab(targetId);
55
+ const client = await connectToTab(targetId, undefined, undefined, undefined, appName);
50
56
  const result = await client.session.Runtime.evaluate({
51
57
  expression: `JSON.stringify({ title: document.title, url: location.href })`,
52
58
  returnByValue: true
@@ -104,17 +110,25 @@ async function enforceMaxTabs(config) {
104
110
  logAction("browser_tabs", victim.id, `auto-closed idle tab: ${victim.title}`);
105
111
  }
106
112
  // ─── Tools ────────────────────────────────────────────────────────────────────
107
- export async function WeavetabOpen(url, config, reuse = true) {
108
- const port = resolvePort(config);
113
+ export async function WeavetabOpen(url, config, reuse = true, appName) {
114
+ // Infer appName from active session if omitted
115
+ let resolvedAppName = appName;
116
+ if (!resolvedAppName) {
117
+ const lastApp = sessionRegistry.getLastActiveApp();
118
+ if (lastApp) {
119
+ resolvedAppName = lastApp;
120
+ }
121
+ }
122
+ const port = resolvePort(config, resolvedAppName);
109
123
  // Tab reuse: if same URL is already open, focus it instead of duplicating
110
124
  if (reuse && url) {
111
125
  try {
112
- const targets = await getTabList(getConfigAgentId(config));
126
+ const targets = await getTabList(getConfigAgentId(config), resolvedAppName);
113
127
  const existing = targets.find((t) => t.url === url);
114
128
  if (existing) {
115
- const client = await connectToTab(existing.id);
129
+ const client = await connectToTab(existing.id, undefined, undefined, undefined, resolvedAppName);
116
130
  await client.session.Target.activateTarget({ targetId: existing.id });
117
- sessionRegistry.setActive(existing.id, getConfigAgentId(config));
131
+ sessionRegistry.setActive(existing.id, getConfigAgentId(config), resolvedAppName);
118
132
  recordTabActivity(existing.id);
119
133
  logAction("browser_tabs", url, `reused existing tab ${existing.id}`);
120
134
  return { success: true, tabId: existing.id, url, reused: true };
@@ -122,22 +136,24 @@ export async function WeavetabOpen(url, config, reuse = true) {
122
136
  }
123
137
  catch { /* fall through to open new */ }
124
138
  }
125
- await enforceMaxTabs(config);
126
- const bctxId = sessionRegistry.getBrowserContextIdForAgent(getConfigAgentId(config));
139
+ if (!resolvedAppName) {
140
+ await enforceMaxTabs(config);
141
+ }
142
+ const bctxId = resolvedAppName ? undefined : sessionRegistry.getBrowserContextIdForAgent(getConfigAgentId(config));
127
143
  const metaSession = await CDP({ host: "127.0.0.1", port });
128
144
  const { targetId } = await metaSession.Target.createTarget({ url, browserContextId: bctxId });
129
145
  await metaSession.close();
130
146
  recordTabActivity(targetId);
131
- await connectToTab(targetId, port, getConfigAgentId(config), bctxId);
132
- await evaluateTabSemantics(targetId);
147
+ await connectToTab(targetId, port, getConfigAgentId(config), bctxId, appName);
148
+ await evaluateTabSemantics(targetId, appName);
133
149
  logAction("browser_tabs", url, `opened ${targetId}`);
134
150
  return { success: true, tabId: targetId, url };
135
151
  }
136
- export async function WeavetabSwitch(tabId, config) {
137
- const client = await connectToTab(tabId);
152
+ export async function WeavetabSwitch(tabId, config, appName) {
153
+ const client = await connectToTab(tabId, undefined, undefined, undefined, appName);
138
154
  const startSwitch = Date.now();
139
155
  await client.session.Target.activateTarget({ targetId: tabId });
140
- sessionRegistry.setActive(tabId, getConfigAgentId(config));
156
+ sessionRegistry.setActive(tabId, getConfigAgentId(config), appName);
141
157
  recordTabActivity(tabId);
142
158
  const { frameTree } = await client.session.Page.getFrameTree();
143
159
  let title = tabId;
@@ -154,9 +170,9 @@ export async function WeavetabSwitch(tabId, config) {
154
170
  resetLoopCounter("tab_switch");
155
171
  return { success: true, tab_id: tabId, title, url, contextSwitchCostMs: cost };
156
172
  }
157
- export async function WeavetabList(config) {
158
- const targets = await getTabList(getConfigAgentId(config));
159
- const activeTargetId = sessionRegistry.getActive(getConfigAgentId(config))?.targetId;
173
+ export async function WeavetabList(config, appName) {
174
+ const targets = await getTabList(getConfigAgentId(config), appName);
175
+ const activeTargetId = sessionRegistry.getActive(getConfigAgentId(config), appName)?.targetId;
160
176
  const tabs = targets
161
177
  .map((t) => ({
162
178
  id: t.id,
@@ -174,12 +190,12 @@ export async function WeavetabList(config) {
174
190
  }));
175
191
  return { tabs };
176
192
  }
177
- export async function WeavetabClose(tabId, config, force = false) {
193
+ export async function WeavetabClose(tabId, config, force = false, appName) {
178
194
  const score = semanticScores.get(tabId) ?? 10;
179
195
  if (score >= 70 && !force) {
180
196
  throw new Error(`[!] Tab Armor block: This tab is semantically protected (score: ${score}). It likely contains a login, checkout, or critical work. Do not close it! If the user explicitly requested this closure, pass force: true.`);
181
197
  }
182
- const port = resolvePort(config);
198
+ const port = resolvePort(config, appName);
183
199
  await CDP.Close({ host: "127.0.0.1", port, id: tabId });
184
200
  clearTabCache(tabId);
185
201
  sessionRegistry.unregister(tabId);
@@ -192,12 +208,12 @@ export async function WeavetabClose(tabId, config, force = false) {
192
208
  /**
193
209
  * Batch close multiple tabs at once — saves multiple round-trips.
194
210
  */
195
- export async function WeavetabCloseBatch(tabIds, config, force = false) {
211
+ export async function WeavetabCloseBatch(tabIds, config, force = false, appName) {
196
212
  const closed = [];
197
213
  const skipped = [];
198
214
  for (const tabId of tabIds) {
199
215
  try {
200
- await WeavetabClose(tabId, config, force);
216
+ await WeavetabClose(tabId, config, force, appName);
201
217
  closed.push(tabId);
202
218
  }
203
219
  catch {
@@ -209,14 +225,14 @@ export async function WeavetabCloseBatch(tabIds, config, force = false) {
209
225
  /**
210
226
  * Consolidate: deduplicate tabs by URL, close duplicates.
211
227
  */
212
- export async function WeavetabConsolidate(config) {
213
- const port = resolvePort(config);
228
+ export async function WeavetabConsolidate(config, appName) {
229
+ const port = resolvePort(config, appName);
214
230
  const targets = await CDP.List({ host: "127.0.0.1", port });
215
- const pages = targets.filter((t) => t.type === "page");
231
+ const pages = targets.filter((t) => t.type === "page" || t.type === "webview" || t.type === "app");
216
232
  const tabsBefore = pages.length;
217
233
  const seenUrls = new Set();
218
234
  let closedDuplicates = 0;
219
- const activeTargetId = sessionRegistry.getActive(getConfigAgentId(config))?.targetId;
235
+ const activeTargetId = sessionRegistry.getActive(getConfigAgentId(config), appName)?.targetId;
220
236
  for (const page of pages) {
221
237
  if (page.id === activeTargetId) {
222
238
  seenUrls.add(page.url);
@@ -240,17 +256,17 @@ export async function WeavetabConsolidate(config) {
240
256
  }
241
257
  }
242
258
  const afterTargets = await CDP.List({ host: "127.0.0.1", port });
243
- const tabsAfter = afterTargets.filter((t) => t.type === "page").length;
259
+ const tabsAfter = afterTargets.filter((t) => t.type === "page" || t.type === "webview" || t.type === "app").length;
244
260
  logAction("browser_tabs", "consolidate", `${tabsBefore}→${tabsAfter} (closed ${closedDuplicates} duplicates)`);
245
261
  return { success: true, tabs_before: tabsBefore, tabs_after: tabsAfter, closed_duplicates: closedDuplicates };
246
262
  }
247
263
  /**
248
264
  * Heal: check all tabs for crashed state and reload them.
249
265
  */
250
- export async function WeavetabHeal(config) {
251
- const port = resolvePort(config);
266
+ export async function WeavetabHeal(config, appName) {
267
+ const port = resolvePort(config, appName);
252
268
  const targets = await CDP.List({ host: "127.0.0.1", port });
253
- const pages = targets.filter((t) => t.type === "page");
269
+ const pages = targets.filter((t) => t.type === "page" || t.type === "webview" || t.type === "app");
254
270
  let healed = 0;
255
271
  const healthSummary = {};
256
272
  for (const page of pages) {
@@ -269,7 +285,7 @@ export async function WeavetabHeal(config) {
269
285
  continue;
270
286
  }
271
287
  try {
272
- const client = await connectToTab(page.id);
288
+ const client = await connectToTab(page.id, undefined, undefined, undefined, appName);
273
289
  const { result } = await client.session.Runtime.evaluate({
274
290
  expression: `document.readyState`,
275
291
  returnByValue: true,
@@ -292,10 +308,10 @@ export async function WeavetabHeal(config) {
292
308
  logAction("browser_tabs", "heal", `healed ${healed}/${pages.length} tabs`);
293
309
  return { success: true, healed, tabs_checked: pages.length, health_summary: healthSummary };
294
310
  }
295
- export async function weaveWindowList(config) {
296
- const port = resolvePort(config);
311
+ export async function weaveWindowList(config, appName) {
312
+ const port = resolvePort(config, appName);
297
313
  const targets = await CDP.List({ host: "127.0.0.1", port });
298
- const pages = targets.filter((t) => t.type === "page");
314
+ const pages = targets.filter((t) => t.type === "page" || t.type === "webview" || t.type === "app");
299
315
  // Group by process — each unique window has its own set of tabs
300
316
  // We approximate via CDP Target.getTargets windowId if available
301
317
  const windows = [];
@@ -307,7 +323,7 @@ export async function weaveWindowList(config) {
307
323
  const { windowId, bounds } = await session.Browser.getWindowForTarget({ targetId: page.id });
308
324
  if (!seenWindowIds.has(windowId)) {
309
325
  seenWindowIds.add(windowId);
310
- const activeId = sessionRegistry.getActive(getConfigAgentId(config))?.targetId;
326
+ const activeId = sessionRegistry.getActive(getConfigAgentId(config), appName)?.targetId;
311
327
  windows.push({
312
328
  windowId,
313
329
  state: bounds.windowState || "normal",
@@ -324,12 +340,12 @@ export async function weaveWindowList(config) {
324
340
  }
325
341
  return { windows };
326
342
  }
327
- export async function weaveFocusWindow(windowId, config) {
328
- const port = resolvePort(config);
343
+ export async function weaveFocusWindow(windowId, config, appName) {
344
+ const port = resolvePort(config, appName);
329
345
  const targets = await CDP.List({ host: "127.0.0.1", port });
330
- const page = targets.find((t) => t.type === "page");
346
+ const page = targets.find((t) => t.type === "page" || t.type === "webview" || t.type === "app");
331
347
  if (!page)
332
- throw new Error("No page target found to focus window");
348
+ throw new Error("No page or window target found to focus window");
333
349
  const session = await CDP({ host: "127.0.0.1", port, target: page.id });
334
350
  try {
335
351
  await session.Browser.setWindowBounds({ windowId, bounds: { windowState: "normal" } });
@@ -2,6 +2,8 @@ import CDP from "chrome-remote-interface";
2
2
  export interface ThoughtOptions {
3
3
  action: "feedback" | "question";
4
4
  message: string;
5
+ anchor?: string;
6
+ style?: "observation" | "decision" | "warning" | "question";
5
7
  input?: "sentence" | "paragraph";
6
8
  timeout?: number;
7
9
  }
@@ -7,32 +7,31 @@ function sleep(ms) {
7
7
  return new Promise(r => setTimeout(r, ms));
8
8
  }
9
9
  export async function browserThought(session, args) {
10
- const { action, message, input, timeout } = args;
10
+ const { action, message, input, timeout, anchor, style } = args;
11
11
  logAction("browser_thought", action, message);
12
12
  if (action === "feedback") {
13
- await sendToExtension(session, {
14
- type: 'Weavetab_STATE',
15
- hud: { action: message },
16
- stickyFeedback: true,
17
- }).catch(() => { });
18
- // Forward to sidepanel thought stream
13
+ // Forward thought event to extension
19
14
  await sendToExtension(session, {
20
15
  type: 'WT_THOUGHT',
21
16
  text: message,
22
17
  kind: 'thought',
18
+ anchor,
19
+ style: style || 'observation',
20
+ action: 'feedback',
23
21
  }).catch(() => { });
24
22
  return { success: true };
25
23
  }
26
24
  if (action === "question") {
27
25
  const QUESTION_TIMEOUT_MS = Math.min((timeout || 20), 20) * 1000;
28
26
  await sendToExtension(session, {
29
- type: 'Weavetab_STATE',
30
- hud: { action: message },
31
- stickyFeedback: true,
32
- ask: {
33
- input: input || "sentence",
34
- timeout: Math.min((timeout || 20), 20),
35
- },
27
+ type: 'WT_THOUGHT',
28
+ text: message,
29
+ kind: 'question',
30
+ anchor,
31
+ style: style || 'question',
32
+ action: 'question',
33
+ input: input || "sentence",
34
+ timeout: Math.min((timeout || 20), 20),
36
35
  }).catch(() => { });
37
36
  const start = Date.now();
38
37
  while (Date.now() - start < QUESTION_TIMEOUT_MS + 5000) {
@@ -48,6 +48,8 @@ export declare function detectFramework(session: CDP.Client): Promise<'react' |
48
48
  export declare function frameworkAwareType(session: CDP.Client, objectId: string, text: string, framework: 'react' | 'vue' | 'angular' | 'vanilla'): Promise<boolean>;
49
49
  export declare function weaveType(session: CDP.Client, args: {
50
50
  id?: string;
51
+ target?: string;
52
+ selector?: string;
51
53
  label?: string;
52
54
  intent?: string;
53
55
  backendNodeId?: number;