@weavetab/mcp 2.5.0-beta.2 → 2.5.0-beta.5

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 (127) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +6 -6
  3. package/LICENSE +216 -631
  4. package/README.md +153 -1074
  5. package/SECURITY.md +33 -22
  6. package/TROUBLESHOOTING.md +2 -2
  7. package/dist/cdp/bridge.js +2 -1
  8. package/dist/cdp/connector.d.ts +2 -0
  9. package/dist/cdp/connector.js +10 -6
  10. package/dist/cdp/helpers.d.ts +4 -0
  11. package/dist/cdp/helpers.js +181 -0
  12. package/dist/cdp/omni_broker.d.ts +1 -1
  13. package/dist/cdp/omni_broker.js +1 -1
  14. package/dist/cdp/walker.d.ts +25 -1
  15. package/dist/cdp/walker.js +304 -7
  16. package/dist/cli/plugin.d.ts +1 -0
  17. package/dist/cli/plugin.js +81 -18
  18. package/dist/cli/updater.d.ts +1 -1
  19. package/dist/cli/updater.js +27 -7
  20. package/dist/config/loader.d.ts +9 -1
  21. package/dist/config/loader.js +42 -3
  22. package/dist/desktop/discovery.d.ts +44 -0
  23. package/dist/desktop/discovery.js +364 -0
  24. package/dist/index.js +137 -21
  25. package/dist/intelligence/marks.d.ts +36 -0
  26. package/dist/intelligence/marks.js +30 -0
  27. package/dist/intelligence/patternCompiler.d.ts +118 -0
  28. package/dist/intelligence/patternCompiler.js +259 -0
  29. package/dist/intelligence/sessionMemory.d.ts +2 -0
  30. package/dist/intelligence/sessionMemory.js +18 -8
  31. package/dist/overlay/injector.js +2 -2
  32. package/dist/plugin/interface.d.ts +88 -5
  33. package/dist/plugin/loader.d.ts +12 -1
  34. package/dist/plugin/loader.js +280 -70
  35. package/dist/plugin/pipeline.d.ts +75 -0
  36. package/dist/plugin/pipeline.js +183 -0
  37. package/dist/plugin/registry.d.ts +2 -1
  38. package/dist/plugin/registry.js +24 -14
  39. package/dist/security/secrets.d.ts +7 -0
  40. package/dist/security/secrets.js +37 -0
  41. package/dist/sensors/actionability.js +1 -2
  42. package/dist/sensors/guard.js +4 -10
  43. package/dist/sensors/mutations.js +12 -0
  44. package/dist/sensors/operation_monitor.js +1 -0
  45. package/dist/server.d.ts +1 -1
  46. package/dist/server.js +453 -178
  47. package/dist/state/agent.d.ts +1 -0
  48. package/dist/state/agent.js +3 -0
  49. package/dist/state/delta.d.ts +12 -4
  50. package/dist/state/delta.js +67 -14
  51. package/dist/state/session.d.ts +6 -0
  52. package/dist/state/session.js +27 -0
  53. package/dist/tools/browser_detect.d.ts +16 -3
  54. package/dist/tools/browser_detect.js +52 -7
  55. package/dist/tools/burst.d.ts +17 -8
  56. package/dist/tools/burst.js +236 -77
  57. package/dist/tools/captcha.js +1 -1
  58. package/dist/tools/checkpoint.d.ts +38 -0
  59. package/dist/tools/checkpoint.js +271 -0
  60. package/dist/tools/click.d.ts +1 -0
  61. package/dist/tools/click.js +74 -70
  62. package/dist/tools/design_extract.js +1 -1
  63. package/dist/tools/eval.js +1 -1
  64. package/dist/tools/fill.d.ts +20 -1
  65. package/dist/tools/fill.js +199 -40
  66. package/dist/tools/find.d.ts +16 -0
  67. package/dist/tools/find.js +67 -44
  68. package/dist/tools/github/index.d.ts +19 -4
  69. package/dist/tools/github/index.js +40 -4
  70. package/dist/tools/highlight.d.ts +6 -2
  71. package/dist/tools/highlight.js +158 -72
  72. package/dist/tools/inspect.js +1 -1
  73. package/dist/tools/key.js +65 -56
  74. package/dist/tools/navigate.d.ts +1 -1
  75. package/dist/tools/navigate.js +34 -39
  76. package/dist/tools/pdf.js +21 -13
  77. package/dist/tools/pointer.d.ts +18 -3
  78. package/dist/tools/pointer.js +89 -1
  79. package/dist/tools/read.d.ts +28 -8
  80. package/dist/tools/read.js +230 -56
  81. package/dist/tools/scrape.js +67 -13
  82. package/dist/tools/screenshot.js +21 -16
  83. package/dist/tools/scroll.js +6 -11
  84. package/dist/tools/select.js +8 -2
  85. package/dist/tools/snapshot.js +3 -34
  86. package/dist/tools/tabs.js +15 -7
  87. package/dist/tools/thought.d.ts +2 -0
  88. package/dist/tools/thought.js +13 -14
  89. package/dist/tools/type.d.ts +2 -0
  90. package/dist/tools/type.js +107 -58
  91. package/dist/tools/type_secret.js +42 -76
  92. package/dist/tools/upload.js +1 -1
  93. package/dist/tools/video_compiler.d.ts +1 -1
  94. package/dist/tools/video_compiler.js +11 -12
  95. package/dist/version.d.ts +5 -0
  96. package/dist/version.js +5 -0
  97. package/docs/DOCUMENTATION.md +37 -41
  98. package/docs/PLUGINS.md +121 -0
  99. package/docs/TOOLS.md +54 -0
  100. package/docs/architecture/blind-injection.md +83 -20
  101. package/docs/architecture/overview.md +49 -49
  102. package/docs/architecture/security.md +8 -7
  103. package/docs/architecture/transport.md +2 -2
  104. package/docs/cli/cli-commands.md +7 -1
  105. package/docs/cli/cli-flags.md +15 -7
  106. package/docs/cli/cli-scripting.md +6 -3
  107. package/docs/configuration/config-locations.md +3 -4
  108. package/docs/configuration/env-variables.md +4 -4
  109. package/docs/configuration/folders.md +55 -54
  110. package/docs/desktop-automation/electron-apps.md +214 -162
  111. package/docs/get-started/introduction.md +60 -60
  112. package/docs/get-started/setup-wizard.md +7 -6
  113. package/docs/intelligence/site-profiles.md +151 -0
  114. package/docs/tools/tools.md +631 -293
  115. package/docs/troubleshooting/trouble-browser.md +1 -1
  116. package/docs/troubleshooting/trouble-loop.md +31 -31
  117. package/ext-dist/background.js +10 -62
  118. package/ext-dist/content.js +333 -920
  119. package/ext-dist/hud/hud.js +9 -9
  120. package/ext-dist/manifest.json +2 -6
  121. package/ext-dist/styles.css +6 -1
  122. package/icon.png +0 -0
  123. package/mcp.json +87 -71
  124. package/package.json +118 -119
  125. package/server.json +5 -5
  126. package/ext-dist/sidepanel/sidepanel.js +0 -25
  127. package/ext-dist/sidepanel.html +0 -547
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Weavetab — intelligence/patternCompiler.ts
3
+ *
4
+ * Compiles raw browser session trails (action sequences) into persistent,
5
+ * reusable site workflow patterns stored under ~/.weavetab-system/memory/sites/.
6
+ *
7
+ * Design invariants:
8
+ * - One file per origin (sanitized hostname). Never creates per-path or per-run files.
9
+ * - Pattern names are caller-supplied (snake_case). Duplicate calls for the same
10
+ * name on the same origin UPDATE the existing pattern rather than creating a new file.
11
+ * - Volatile / unstable selectors (auto-generated classes, nth-child paths) are
12
+ * stripped and replaced with semantic anchors where possible.
13
+ * - Never reads or writes to ~/.weavetab/ (user config space).
14
+ */
15
+ import { readFile, writeFile } from "fs/promises";
16
+ import { join } from "path";
17
+ import fs from "fs";
18
+ import { getSystemMemorySitesDir } from "../config/loader.js";
19
+ import { logDebug } from "../audit/logger.js";
20
+ // ─── Volatile selector detection ────────────────────────────────────────────
21
+ const VOLATILE_PATTERNS = [
22
+ /\[class\*="[a-z0-9]+-[a-z0-9]+"\]/, // CSS-module hash attribute selectors
23
+ /:nth-child\(\d+\)/, // positional pseudo-selectors
24
+ /\.\w{8,}[-_]\w{4,}/, // hashed Tailwind / CSS-module class combos
25
+ /div > div > div > /, // deep anonymous structural chains (3+ levels)
26
+ ];
27
+ function isVolatileSelector(sel) {
28
+ return VOLATILE_PATTERNS.some((rx) => rx.test(sel));
29
+ }
30
+ function stabilizeSelector(sel) {
31
+ if (!sel)
32
+ return undefined;
33
+ if (isVolatileSelector(sel)) {
34
+ logDebug(`[PatternCompiler] Dropping volatile selector: ${sel}`);
35
+ return undefined;
36
+ }
37
+ return sel;
38
+ }
39
+ // ─── File path helpers ───────────────────────────────────────────────────────
40
+ function originToFilename(origin) {
41
+ return origin
42
+ .replace(/^https?:\/\//, "")
43
+ .replace(/[^a-zA-Z0-9.-]/g, "_");
44
+ }
45
+ function siteProfilePath(origin) {
46
+ const sitesDir = getSystemMemorySitesDir();
47
+ return join(sitesDir, `${originToFilename(origin)}.json`);
48
+ }
49
+ // ─── In-process LRU cache ───────────────────────────────────────────────────
50
+ const profileCache = new Map();
51
+ const CACHE_MAX = 100;
52
+ function cacheSet(origin, profile) {
53
+ if (profileCache.size >= CACHE_MAX && !profileCache.has(origin)) {
54
+ const firstKey = profileCache.keys().next().value;
55
+ if (firstKey !== undefined)
56
+ profileCache.delete(firstKey);
57
+ }
58
+ profileCache.set(origin, profile);
59
+ }
60
+ export function clearSiteProfileCache() {
61
+ profileCache.clear();
62
+ }
63
+ // ─── Public API ──────────────────────────────────────────────────────────────
64
+ /**
65
+ * Load a site profile from disk. Returns null if the site has never been profiled.
66
+ * Hits in-process cache first — no redundant disk reads within a session.
67
+ */
68
+ export async function getSiteProfile(origin) {
69
+ if (profileCache.has(origin))
70
+ return profileCache.get(origin);
71
+ const filePath = siteProfilePath(origin);
72
+ if (!fs.existsSync(filePath))
73
+ return null;
74
+ try {
75
+ const raw = await readFile(filePath, "utf-8");
76
+ const profile = JSON.parse(raw);
77
+ cacheSet(origin, profile);
78
+ return profile;
79
+ }
80
+ catch (e) {
81
+ logDebug(`[PatternCompiler] Failed to parse site profile for ${origin}: ${e}`);
82
+ return null;
83
+ }
84
+ }
85
+ /**
86
+ * Persist a site profile. Always deep-merges into existing data on disk — never
87
+ * blindly overwrites — so concurrent tool calls don't clobber each other.
88
+ */
89
+ export async function saveSiteProfile(profile) {
90
+ const filePath = siteProfilePath(profile.origin);
91
+ let base = null;
92
+ if (fs.existsSync(filePath)) {
93
+ try {
94
+ base = JSON.parse(await readFile(filePath, "utf-8"));
95
+ }
96
+ catch { /* treat corrupt file as empty */ }
97
+ }
98
+ const merged = {
99
+ ...base,
100
+ ...profile,
101
+ origin: profile.origin,
102
+ patterns: { ...(base?.patterns ?? {}), ...profile.patterns },
103
+ quirks: { ...(base?.quirks ?? {}), ...profile.quirks },
104
+ visitCount: profile.visitCount ?? base?.visitCount ?? 0,
105
+ updatedAt: new Date().toISOString(),
106
+ };
107
+ cacheSet(profile.origin, merged);
108
+ await writeFile(filePath, JSON.stringify(merged, null, 2), "utf-8");
109
+ logDebug(`[PatternCompiler] Saved site profile → ${filePath}`);
110
+ }
111
+ /**
112
+ * Learn or update a named workflow pattern for a given origin.
113
+ * - Duplicate name = merge/update, never duplicate file.
114
+ * - Volatile selectors in steps are dropped to keep patterns stable.
115
+ * - Anti-spam: skips disk write when content is identical to existing.
116
+ */
117
+ export async function learnPattern(origin, name, incoming) {
118
+ const profile = (await getSiteProfile(origin)) ?? {
119
+ origin,
120
+ quirks: {},
121
+ patterns: {},
122
+ visitCount: 0,
123
+ updatedAt: new Date().toISOString(),
124
+ };
125
+ const existing = profile.patterns[name] ?? {
126
+ name,
127
+ steps: [],
128
+ reliability: 1.0,
129
+ strikes: 0,
130
+ last_verified: new Date().toISOString(),
131
+ total_executions: 0,
132
+ successful_executions: 0,
133
+ };
134
+ const stabilizedSteps = (incoming.steps ?? existing.steps).map((step) => ({
135
+ ...step,
136
+ target: step.target ? stabilizeSelector(step.target) : undefined,
137
+ }));
138
+ const hasChanges = (!profile.patterns[name] ||
139
+ (incoming.steps !== undefined && JSON.stringify(stabilizedSteps) !== JSON.stringify(existing.steps)) ||
140
+ (incoming.success_indicator !== undefined && incoming.success_indicator !== existing.success_indicator) ||
141
+ (incoming.entry !== undefined && incoming.entry !== existing.entry));
142
+ if (hasChanges) {
143
+ const updated = {
144
+ ...existing,
145
+ ...incoming,
146
+ name,
147
+ steps: stabilizedSteps,
148
+ last_verified: new Date().toISOString(),
149
+ };
150
+ await saveSiteProfile({
151
+ ...profile,
152
+ patterns: { ...profile.patterns, [name]: updated },
153
+ });
154
+ logDebug(`[PatternCompiler] Pattern "${name}" learned/updated for ${origin}`);
155
+ return updated;
156
+ }
157
+ else {
158
+ logDebug(`[PatternCompiler] Pattern "${name}" unchanged — skipping write`);
159
+ return existing;
160
+ }
161
+ }
162
+ /**
163
+ * Record the outcome of executing a named pattern.
164
+ * Updates reliability via EWMA (α=0.15) and tracks consecutive strikes.
165
+ * 3 strikes → reliability will naturally fall below 0.4, agent should re-explore.
166
+ */
167
+ export async function recordPatternExecution(origin, patternName, success, durationMs) {
168
+ const profile = await getSiteProfile(origin);
169
+ if (!profile)
170
+ return null;
171
+ const pattern = profile.patterns[patternName];
172
+ if (!pattern)
173
+ return null;
174
+ const alpha = 0.15;
175
+ const newReliability = Math.round((0.85 * pattern.reliability + alpha * (success ? 1 : 0)) * 1000) / 1000;
176
+ const updated = {
177
+ ...pattern,
178
+ reliability: newReliability,
179
+ strikes: success ? 0 : pattern.strikes + 1,
180
+ last_verified: success ? new Date().toISOString() : pattern.last_verified,
181
+ total_executions: pattern.total_executions + 1,
182
+ successful_executions: success ? pattern.successful_executions + 1 : pattern.successful_executions,
183
+ avg_duration_ms: durationMs !== undefined
184
+ ? Math.round(pattern.avg_duration_ms !== undefined
185
+ ? 0.8 * pattern.avg_duration_ms + 0.2 * durationMs
186
+ : durationMs)
187
+ : pattern.avg_duration_ms,
188
+ };
189
+ if (updated.strikes >= 3) {
190
+ logDebug(`[PatternCompiler] ⚠ Pattern "${patternName}" on ${origin} hit 3 strikes (reliability: ${updated.reliability}) — re-learning recommended`);
191
+ }
192
+ await saveSiteProfile({
193
+ ...profile,
194
+ patterns: { ...profile.patterns, [patternName]: updated },
195
+ });
196
+ return updated;
197
+ }
198
+ /**
199
+ * Record or update a site quirk (cookie banner, rate limit, modal popup, etc.)
200
+ * Only writes if the stored data differs from incoming — prevents spam writes.
201
+ */
202
+ export async function recordQuirk(origin, quirkKey, quirkData) {
203
+ const profile = (await getSiteProfile(origin)) ?? {
204
+ origin,
205
+ quirks: {},
206
+ patterns: {},
207
+ visitCount: 0,
208
+ updatedAt: new Date().toISOString(),
209
+ };
210
+ const existing = profile.quirks[quirkKey];
211
+ if (JSON.stringify(existing) === JSON.stringify(quirkData)) {
212
+ logDebug(`[PatternCompiler] Quirk "${quirkKey}" unchanged — skipping write`);
213
+ return;
214
+ }
215
+ await saveSiteProfile({
216
+ ...profile,
217
+ quirks: { ...profile.quirks, [quirkKey]: quirkData },
218
+ });
219
+ logDebug(`[PatternCompiler] Recorded quirk "${quirkKey}" for ${origin}`);
220
+ }
221
+ /**
222
+ * Returns the reliability score (0–1) of a named pattern, or -1 if unknown.
223
+ */
224
+ export async function getPatternReliability(origin, patternName) {
225
+ const profile = await getSiteProfile(origin);
226
+ if (!profile)
227
+ return -1;
228
+ return profile.patterns[patternName]?.reliability ?? -1;
229
+ }
230
+ /**
231
+ * Formats a compact site profile hint string for agent system prompt injection.
232
+ * Called at session start when navigating to a known origin.
233
+ */
234
+ export function formatSiteProfileHint(profile) {
235
+ const lines = [`[SiteProfile] ${profile.origin}`];
236
+ if (profile.framework)
237
+ lines.push(` framework: ${profile.framework}`);
238
+ if (profile.captcha_frequency && profile.captcha_frequency !== "none") {
239
+ lines.push(` captcha_frequency: ${profile.captcha_frequency}`);
240
+ }
241
+ const patternNames = Object.keys(profile.patterns);
242
+ if (patternNames.length > 0) {
243
+ lines.push(" known_patterns:");
244
+ for (const name of patternNames) {
245
+ const p = profile.patterns[name];
246
+ const flag = p.strikes >= 3
247
+ ? " [RE-LEARN NEEDED]"
248
+ : p.reliability >= 0.8
249
+ ? " [fast-path eligible]"
250
+ : "";
251
+ lines.push(` - ${name}: reliability=${p.reliability.toFixed(2)}, steps=${p.steps.length}${flag}`);
252
+ }
253
+ }
254
+ const quirkKeys = Object.keys(profile.quirks).filter((k) => profile.quirks[k] !== undefined && profile.quirks[k] !== null);
255
+ if (quirkKeys.length > 0) {
256
+ lines.push(` quirks: ${quirkKeys.join(", ")}`);
257
+ }
258
+ return lines.join("\n");
259
+ }
@@ -34,6 +34,8 @@ export interface DomainProfile {
34
34
  updatedAt: string;
35
35
  visitCount: number;
36
36
  }
37
+ export declare function clearMemoryCache(): void;
38
+ export declare function getDomainFilePath(hostname: string): string;
37
39
  export declare function loadDomainProfile(hostname: string): Promise<DomainProfile | null>;
38
40
  export declare function saveDomainProfile(hostname: string, updates: Partial<DomainProfile>): Promise<DomainProfile>;
39
41
  /**
@@ -1,20 +1,30 @@
1
1
  import { readFile, writeFile } from "fs/promises";
2
2
  import { join } from "path";
3
- import { GLOBAL_CONFIG_DIR } from "../config/loader.js";
3
+ import { GLOBAL_CONFIG_DIR, getSystemDir } from "../config/loader.js";
4
4
  import { logDebug } from "../audit/logger.js";
5
5
  import fs from "fs";
6
6
  function domainFile(hostname) {
7
7
  const safe = hostname.replace(/[^a-zA-Z0-9.-]/g, "_");
8
- const memoryDir = join(GLOBAL_CONFIG_DIR, "memory");
9
- if (!fs.existsSync(memoryDir))
10
- fs.mkdirSync(memoryDir, { recursive: true });
11
- return join(memoryDir, `${safe}.json`);
8
+ const memoryDir = getSystemDir("memory");
9
+ const systemPath = join(memoryDir, `${safe}.json`);
10
+ // Backward compatibility: migrate legacy ~/.weavetab/memory/<safe>.json if it exists
11
+ const legacyPath = join(GLOBAL_CONFIG_DIR, "memory", `${safe}.json`);
12
+ if (!fs.existsSync(systemPath) && fs.existsSync(legacyPath)) {
13
+ try {
14
+ fs.copyFileSync(legacyPath, systemPath);
15
+ }
16
+ catch { /* ignore migration error */ }
17
+ }
18
+ return systemPath;
12
19
  }
13
- // memoryCache is capped at 200 DomainProfile entries (one per unique hostname).
14
- // When the cap is hit, the oldest entry is evicted (insertion-order LRU) so the
15
- // cache can't grow without bound over a long session.
16
20
  const memoryCache = new Map();
17
21
  const MEMORY_CACHE_MAX = 200;
22
+ export function clearMemoryCache() {
23
+ memoryCache.clear();
24
+ }
25
+ export function getDomainFilePath(hostname) {
26
+ return domainFile(hostname);
27
+ }
18
28
  function memoryCacheSet(hostname, profile) {
19
29
  if (memoryCache.size >= MEMORY_CACHE_MAX && !memoryCache.has(hostname)) {
20
30
  // Evict the oldest (first) entry
@@ -152,7 +152,7 @@ export async function ensureVisualLayer(session, config, client) {
152
152
  returnByValue: true
153
153
  });
154
154
  if (checkResult?.value) {
155
- logDebug(`[Weavetab] [OK] Minimal overlay injected successfully`);
155
+ logDebug(`[Weavetab] overlay injected`);
156
156
  }
157
157
  else {
158
158
  logDebug(`[Weavetab] [!] Minimal overlay injection failed - element not found`);
@@ -171,7 +171,7 @@ export async function setupOverlay(session, config) {
171
171
  await ensureVisualLayer(session, config);
172
172
  }
173
173
  export async function setFaviconState(_session, _state) {
174
- // Handled robustly via extension content.js
174
+ // handled via extension content.js
175
175
  }
176
176
  export async function removeTitleBadge(_session) {
177
177
  // No-op: title dot prefix removed in favor of favicon indicators
@@ -57,22 +57,36 @@ export interface WeavetabPermissions {
57
57
  reason?: string;
58
58
  [key: string]: any;
59
59
  };
60
+ /** @deprecated use `filesystem` */
60
61
  fs?: {
61
62
  read?: string[];
62
63
  write?: string[];
63
64
  reason?: string;
64
65
  };
66
+ filesystem?: {
67
+ read?: string[];
68
+ write?: string[];
69
+ reason?: string;
70
+ };
65
71
  tools?: {
66
- /** List of built-in tool names this plugin is permitted to override */
72
+ /** Must be true for the plugin to register any new MCP tools */
73
+ add?: boolean;
74
+ /** Explicit list of built-in tool names this plugin may override */
67
75
  override?: string[];
68
- /** List of built-in tool names this plugin is permitted to remove */
76
+ /** Explicit list of built-in tool names this plugin may remove */
69
77
  remove?: string[];
70
- hooks?: boolean;
78
+ reason?: string;
79
+ };
80
+ hooks?: {
81
+ onBeforeAction?: boolean;
82
+ onAfterAction?: boolean;
83
+ onDOMMutation?: boolean;
84
+ onPageNavigate?: boolean;
71
85
  reason?: string;
72
86
  };
73
87
  [key: string]: any;
74
88
  }
75
- export type WeavetabManifestPermissions = WeavetabPermissions;
89
+ export type WeavetabManifestPermissions = WeavetabPermissions | string[];
76
90
  export interface WeavetabManifestAuthor {
77
91
  name: string;
78
92
  role?: string;
@@ -96,6 +110,8 @@ export interface WeavetabManifest {
96
110
  version: string;
97
111
  /** Short summary of what this plugin provides */
98
112
  description?: string;
113
+ /** Entry point file relative to the plugin root (e.g., 'dist/index.js') */
114
+ entry?: string;
99
115
  /** Single author or multiple authors with roles */
100
116
  author?: string | WeavetabManifestAuthor | (string | WeavetabManifestAuthor)[];
101
117
  /** Array of authors */
@@ -119,7 +135,7 @@ export interface WeavetabManifest {
119
135
  /** Default configuration template */
120
136
  defaultConfig?: Record<string, any>;
121
137
  /** Required permissions with security rationale */
122
- permissions?: WeavetabPermissions;
138
+ permissions?: WeavetabManifestPermissions;
123
139
  /** Open source license */
124
140
  license?: string;
125
141
  [key: string]: any;
@@ -132,7 +148,57 @@ export interface WeavetabPluginTool<TArgs = any> {
132
148
  parameters?: Record<string, any>;
133
149
  handler: (args: TArgs, session?: any, config?: any) => Promise<any>;
134
150
  }
151
+ export interface DOMMutationDelta {
152
+ type?: "cdp_mutation" | "action_delta" | "page_update" | "dom_diff" | "rich_delta" | string;
153
+ timestamp?: number;
154
+ url?: string;
155
+ added?: Array<{
156
+ id?: string;
157
+ role?: string;
158
+ label?: string;
159
+ tag?: string;
160
+ text?: string;
161
+ backendNodeId?: number;
162
+ [key: string]: any;
163
+ }>;
164
+ removed?: Array<string | {
165
+ backendNodeId?: number;
166
+ tag?: string;
167
+ text?: string;
168
+ [key: string]: any;
169
+ }>;
170
+ changed?: Array<{
171
+ ref?: string;
172
+ role?: string;
173
+ label?: string;
174
+ attribute?: string;
175
+ oldValue?: any;
176
+ newValue?: any;
177
+ changes?: Record<string, {
178
+ from: any;
179
+ to: any;
180
+ }>;
181
+ actionable?: boolean;
182
+ [key: string]: any;
183
+ }>;
184
+ significantChange?: boolean;
185
+ stable_count?: number;
186
+ iframes?: any[];
187
+ [key: string]: any;
188
+ }
189
+ export type BeforeActionHook = (tool: string, args: Record<string, any>, session?: any) => Promise<Record<string, any> | {
190
+ __blocked: boolean;
191
+ reason?: string;
192
+ } | void> | Record<string, any> | {
193
+ __blocked: boolean;
194
+ reason?: string;
195
+ } | void;
196
+ export type AfterActionHook = (tool: string, result: any, session?: any, args?: Record<string, any>) => Promise<any> | any;
197
+ export type DOMMutationHook = (delta: DOMMutationDelta, session?: any) => Promise<void> | void;
135
198
  export interface PluginHooksContext {
199
+ onBeforeAction: (handler: BeforeActionHook) => void;
200
+ onAfterAction: (handler: AfterActionHook) => void;
201
+ onDOMMutation: (handler: DOMMutationHook) => void;
136
202
  beforeToolCall: (handler: (toolName: string, args: Record<string, any>, session?: any) => Promise<any> | void) => void;
137
203
  afterToolCall: (handler: (toolName: string, args: Record<string, any>, result: any, session?: any) => Promise<any> | void) => void;
138
204
  onPageNavigate?: (handler: (url: string, session?: any) => Promise<void> | void) => void;
@@ -144,6 +210,13 @@ export interface PluginMcpContext {
144
210
  unregisterTool?: (toolName: string) => void;
145
211
  [key: string]: any;
146
212
  }
213
+ export interface PluginMemoryContext {
214
+ getSiteProfile(origin: string): Promise<any>;
215
+ learnPattern(origin: string, name: string, pattern: any): Promise<any>;
216
+ recordExecution(origin: string, name: string, success: boolean, durationMs?: number): Promise<any>;
217
+ getReliability(origin: string, patternName: string): Promise<number>;
218
+ recordQuirk(origin: string, quirkKey: string, quirkData: any): Promise<void>;
219
+ }
147
220
  export interface PluginContext {
148
221
  name: string;
149
222
  version?: string;
@@ -153,6 +226,7 @@ export interface PluginContext {
153
226
  extension: IPluginExtensionBridge;
154
227
  mcp: PluginMcpContext;
155
228
  hooks: PluginHooksContext;
229
+ memory?: PluginMemoryContext;
156
230
  logger: {
157
231
  info: (...args: any[]) => void;
158
232
  warn: (...args: any[]) => void;
@@ -169,6 +243,10 @@ export interface WeavetabPluginDefinition {
169
243
  overrides?: WeavetabToolOverride[];
170
244
  removeTools?: string[];
171
245
  defaultConfig?: Record<string, any>;
246
+ permissions?: WeavetabPermissions;
247
+ onBeforeAction?: BeforeActionHook;
248
+ onAfterAction?: AfterActionHook;
249
+ onDOMMutation?: DOMMutationHook;
172
250
  onLoad?: (ctx: PluginContext) => Promise<void> | void;
173
251
  onUnload?: (ctx: PluginContext) => Promise<void> | void;
174
252
  }
@@ -176,6 +254,7 @@ export interface WeavetabPlugin {
176
254
  name: string;
177
255
  version: string;
178
256
  description?: string;
257
+ permissions?: WeavetabPermissions;
179
258
  /** Add new tools */
180
259
  tools?: WeavetabToolDefinition[] | WeavetabPluginTool[];
181
260
  /** Override or wrap existing tools */
@@ -189,8 +268,12 @@ export interface WeavetabPlugin {
189
268
  hooks?: {
190
269
  beforeToolCall: Array<(toolName: string, args: Record<string, any>, session?: any) => Promise<any> | void>;
191
270
  afterToolCall: Array<(toolName: string, args: Record<string, any>, result: any, session?: any) => Promise<any> | void>;
271
+ onDOMMutation: Array<DOMMutationHook>;
192
272
  onPageNavigate: Array<(url: string, session?: any) => Promise<void> | void>;
193
273
  };
274
+ onBeforeAction?: BeforeActionHook;
275
+ onAfterAction?: AfterActionHook;
276
+ onDOMMutation?: DOMMutationHook;
194
277
  onLoad?: (ctx: PluginContext) => Promise<void> | void;
195
278
  onUnload?: (ctx: PluginContext) => Promise<void> | void;
196
279
  }
@@ -1,4 +1,6 @@
1
- import type { WeavetabPlugin, WeavetabManifest } from "./interface.js";
1
+ import type { WeavetabPlugin, WeavetabManifest, WeavetabPermissions, PluginContext } from "./interface.js";
2
+ import { PluginStorageManager } from "./storage.js";
3
+ import { PluginExtensionBridge } from "./extension_bridge.js";
2
4
  export interface InstalledPluginInfo {
3
5
  packageName: string;
4
6
  dir: string;
@@ -6,6 +8,10 @@ export interface InstalledPluginInfo {
6
8
  pkgJson?: Record<string, any>;
7
9
  hasValidManifest: boolean;
8
10
  }
11
+ /**
12
+ * Normalizes permissions format across legacy arrays and object aliases (filesystem vs fs).
13
+ */
14
+ export declare function normalizePermissions(perms?: any): WeavetabPermissions;
9
15
  /**
10
16
  * Reads the manifest (weavetab.json) and package.json for an installed package
11
17
  * without executing its runtime code (safe for listing/inspection).
@@ -15,6 +21,11 @@ export declare function inspectInstalledPackage(pkgDir: string): InstalledPlugin
15
21
  * Scan node_modules and return metadata for all installed Weavetab plugins.
16
22
  */
17
23
  export declare function listInstalledPlugins(pluginDir?: string): InstalledPluginInfo[];
24
+ export declare function buildPluginContext(plugin: WeavetabPlugin, storageManager: PluginStorageManager, extensionBridge: PluginExtensionBridge, pluginConfig: Record<string, any>, hooks: {
25
+ beforeToolCall: Array<(toolName: string, args: Record<string, any>, session?: any) => Promise<any> | void>;
26
+ afterToolCall: Array<(toolName: string, args: Record<string, any>, result: any, session?: any) => Promise<any> | void>;
27
+ onPageNavigate: Array<(url: string, session?: any) => Promise<void> | void>;
28
+ }): PluginContext;
18
29
  export declare function discoverPlugins(pluginDir?: string): WeavetabPlugin[];
19
30
  /**
20
31
  * Loads a specific plugin by name from node_modules.