@weavetab/mcp 2.5.0-beta.2 → 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 (113) hide show
  1. package/AGENTS.md +1 -1
  2. package/ARCHITECTURE.md +6 -6
  3. package/LICENSE +1 -1
  4. package/README.md +158 -961
  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 +8 -4
  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.js +24 -17
  17. package/dist/cli/updater.d.ts +1 -1
  18. package/dist/cli/updater.js +27 -7
  19. package/dist/config/loader.d.ts +8 -0
  20. package/dist/config/loader.js +41 -2
  21. package/dist/desktop/discovery.d.ts +44 -0
  22. package/dist/desktop/discovery.js +364 -0
  23. package/dist/index.js +95 -15
  24. package/dist/intelligence/marks.d.ts +36 -0
  25. package/dist/intelligence/marks.js +30 -0
  26. package/dist/intelligence/patternCompiler.d.ts +118 -0
  27. package/dist/intelligence/patternCompiler.js +259 -0
  28. package/dist/intelligence/sessionMemory.d.ts +2 -0
  29. package/dist/intelligence/sessionMemory.js +18 -8
  30. package/dist/overlay/injector.js +2 -2
  31. package/dist/plugin/interface.d.ts +76 -2
  32. package/dist/plugin/loader.d.ts +15 -1
  33. package/dist/plugin/loader.js +217 -70
  34. package/dist/plugin/pipeline.d.ts +75 -0
  35. package/dist/plugin/pipeline.js +183 -0
  36. package/dist/plugin/registry.js +3 -2
  37. package/dist/security/secrets.d.ts +1 -0
  38. package/dist/security/secrets.js +13 -0
  39. package/dist/sensors/actionability.js +1 -2
  40. package/dist/sensors/guard.js +4 -10
  41. package/dist/sensors/mutations.js +12 -0
  42. package/dist/sensors/operation_monitor.js +1 -0
  43. package/dist/server.d.ts +1 -1
  44. package/dist/server.js +428 -156
  45. package/dist/state/agent.d.ts +1 -0
  46. package/dist/state/agent.js +3 -0
  47. package/dist/state/delta.d.ts +12 -4
  48. package/dist/state/delta.js +67 -14
  49. package/dist/state/session.d.ts +6 -0
  50. package/dist/state/session.js +27 -0
  51. package/dist/tools/browser_detect.d.ts +16 -3
  52. package/dist/tools/browser_detect.js +50 -5
  53. package/dist/tools/burst.d.ts +17 -8
  54. package/dist/tools/burst.js +236 -77
  55. package/dist/tools/checkpoint.d.ts +38 -0
  56. package/dist/tools/checkpoint.js +271 -0
  57. package/dist/tools/click.d.ts +1 -0
  58. package/dist/tools/click.js +74 -70
  59. package/dist/tools/design_extract.js +1 -1
  60. package/dist/tools/eval.js +1 -1
  61. package/dist/tools/fill.d.ts +20 -1
  62. package/dist/tools/fill.js +199 -40
  63. package/dist/tools/find.d.ts +16 -0
  64. package/dist/tools/find.js +67 -44
  65. package/dist/tools/github/index.d.ts +19 -4
  66. package/dist/tools/github/index.js +40 -4
  67. package/dist/tools/highlight.d.ts +6 -2
  68. package/dist/tools/highlight.js +158 -72
  69. package/dist/tools/inspect.js +1 -1
  70. package/dist/tools/key.js +65 -56
  71. package/dist/tools/navigate.js +29 -34
  72. package/dist/tools/pdf.js +21 -13
  73. package/dist/tools/pointer.d.ts +18 -3
  74. package/dist/tools/pointer.js +89 -1
  75. package/dist/tools/read.d.ts +28 -8
  76. package/dist/tools/read.js +230 -56
  77. package/dist/tools/scrape.js +67 -13
  78. package/dist/tools/screenshot.js +21 -16
  79. package/dist/tools/scroll.js +6 -11
  80. package/dist/tools/select.js +8 -2
  81. package/dist/tools/snapshot.js +3 -34
  82. package/dist/tools/tabs.js +14 -6
  83. package/dist/tools/thought.d.ts +2 -0
  84. package/dist/tools/thought.js +13 -14
  85. package/dist/tools/type.d.ts +2 -0
  86. package/dist/tools/type.js +107 -58
  87. package/dist/tools/type_secret.js +42 -76
  88. package/dist/tools/upload.js +1 -1
  89. package/dist/tools/video_compiler.d.ts +1 -1
  90. package/dist/tools/video_compiler.js +11 -12
  91. package/dist/version.d.ts +5 -0
  92. package/dist/version.js +5 -0
  93. package/docs/DOCUMENTATION.md +21 -32
  94. package/docs/PLUGINS.md +121 -0
  95. package/docs/TOOLS.md +56 -0
  96. package/docs/architecture/blind-injection.md +83 -20
  97. package/docs/architecture/overview.md +49 -49
  98. package/docs/configuration/folders.md +55 -54
  99. package/docs/desktop-automation/electron-apps.md +217 -162
  100. package/docs/get-started/introduction.md +60 -60
  101. package/docs/intelligence/site-profiles.md +151 -0
  102. package/docs/tools/tools.md +631 -293
  103. package/docs/troubleshooting/trouble-loop.md +31 -31
  104. package/ext-dist/background.js +10 -62
  105. package/ext-dist/content.js +333 -920
  106. package/ext-dist/hud/hud.js +9 -9
  107. package/ext-dist/manifest.json +2 -6
  108. package/ext-dist/styles.css +6 -1
  109. package/mcp.json +101 -67
  110. package/package.json +5 -6
  111. package/server.json +3 -3
  112. package/ext-dist/sidepanel/sidepanel.js +0 -25
  113. package/ext-dist/sidepanel.html +0 -547
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import { createRequire } from "node:module";
11
11
  import chalk from "chalk";
12
12
  import boxen from "boxen";
13
13
  import pc from "picocolors";
14
+ import { WEAVETAB_VERSION } from "./version.js";
14
15
  // ─── Server-Process Singleton Lock ────────────────────────────────────────────
15
16
  // When an IDE opens multiple windows or reconnects after a crash, it spawns a new
16
17
  // `node dist/index.js` MCP process each time. Without a guard, these stack up
@@ -32,13 +33,29 @@ function _acquireServerLock() {
32
33
  fs.mkdirSync(_SERVER_LOCK_DIR, { recursive: true });
33
34
  if (fs.existsSync(_SERVER_LOCK_FILE)) {
34
35
  const existingPid = parseInt(fs.readFileSync(_SERVER_LOCK_FILE, "utf-8").trim(), 10);
35
- if (!isNaN(existingPid) && existingPid !== process.pid && _isProcessAlive(existingPid)) {
36
- process.stderr.write(`[Weavetab] Another Weavetab MCP server is running (PID ${existingPid}). Multiple clients active.\n`);
37
- // We no longer return false here. The analyticsInterval.unref() call
38
- // prevents zombie leaks, so it's safe to allow multiple agents (e.g.
39
- // Openchamber + Antigravity) to run their own MCP processes concurrently
40
- // and share the browser.
36
+ if (!isNaN(existingPid) && existingPid !== process.pid) {
37
+ if (_isProcessAlive(existingPid)) {
38
+ process.stderr.write(`[Weavetab] Another Weavetab MCP server is running (PID ${existingPid}). Client session active.\n`);
39
+ }
40
+ else {
41
+ // Process is dead: reap stale PID lock
42
+ try {
43
+ fs.unlinkSync(_SERVER_LOCK_FILE);
44
+ }
45
+ catch { /* ignore */ }
46
+ }
47
+ }
48
+ }
49
+ // Also reap stale browser lock file if the recorded browser PID is dead
50
+ const browserLockFile = path.join(_SERVER_LOCK_DIR, ".weavetab.lock");
51
+ if (fs.existsSync(browserLockFile)) {
52
+ try {
53
+ const lockData = JSON.parse(fs.readFileSync(browserLockFile, "utf-8"));
54
+ if (lockData.pid && !_isProcessAlive(lockData.pid)) {
55
+ fs.unlinkSync(browserLockFile);
56
+ }
41
57
  }
58
+ catch { /* malformed lock, ignore */ }
42
59
  }
43
60
  fs.writeFileSync(_SERVER_LOCK_FILE, String(process.pid), "utf-8");
44
61
  return true;
@@ -134,6 +151,17 @@ async function main() {
134
151
  await runPluginCli(args.slice(1));
135
152
  process.exit(0);
136
153
  }
154
+ if (cmd === "skills") {
155
+ const { execSync: exec } = await import("node:child_process");
156
+ const subArgs = args.slice(1).join(" ");
157
+ try {
158
+ exec(`npx -y @weavetab/skills@latest ${subArgs}`.trim(), { stdio: "inherit" });
159
+ }
160
+ catch {
161
+ process.exit(1);
162
+ }
163
+ process.exit(0);
164
+ }
137
165
  if (cmd === "init" || cmd === "create" || cmd === "build" || cmd === "manifest") {
138
166
  console.log(pc.yellow(`\n[Weavetab] Plugin authoring commands are part of the developer SDK (@weavetab/sdk).`));
139
167
  console.log(pc.dim("To scaffold a new plugin: ") + pc.cyan("npx -y @weavetab/sdk init <name>"));
@@ -406,6 +434,7 @@ async function main() {
406
434
  }, "browserType"),
407
435
  S.cf("Enable Weavetab browser extension?", "extension", true),
408
436
  S.cf("Persist cookies across sessions?", "cookies", false),
437
+ S.cf("Sync browser data across profiles?", "syncDataAcrossBrowsers", false),
409
438
  S.tx("Extra browser flags (space-separated)", "browserFlagsRaw", ""),
410
439
  S.tx("Custom browser profile directory", "profileDir", ""),
411
440
  ])) === "back")
@@ -427,6 +456,8 @@ async function main() {
427
456
  return "Positive integer."; }),
428
457
  S.tx("Actionability timeout (ms)", "actionabilityTimeout", "500", (v) => { const n = parseInt(v ?? ""); if (isNaN(n) || n < 100)
429
458
  return "Min 100 ms."; }),
459
+ S.tx("Ref cache TTL (ms) — stale element handle expiry", "refCacheTtlMs", "30000", (v) => { const n = parseInt(v ?? ""); if (isNaN(n) || n < 1000)
460
+ return "Min 1000 ms."; }),
430
461
  ])) === "back")
431
462
  process.exit(0);
432
463
  }
@@ -445,6 +476,10 @@ async function main() {
445
476
  console.log(boxen(pc.cyan("SECTION D: STORAGE & PROXY"), { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
446
477
  if ((await run([
447
478
  S.tx("Download directory", "downloadDir", ""),
479
+ S.tx("PDF output directory", "pdfDir", ""),
480
+ S.tx("Snapshot directory (screenshots)", "snapshotDir", ""),
481
+ S.tx("Recording output directory", "recordingDir", ""),
482
+ S.tx("Design extraction directory", "designDir", ""),
448
483
  S.tx("Proxy URL (or $WT_PROXY_URL)", "proxy", ""),
449
484
  ])) === "back")
450
485
  process.exit(0);
@@ -492,6 +527,7 @@ async function main() {
492
527
  browserType: a.browserType || "chromium",
493
528
  extension: a.extension !== undefined ? a.extension : true,
494
529
  cookies: a.cookies || false,
530
+ syncDataAcrossBrowsers: a.syncDataAcrossBrowsers || false,
495
531
  browserFlags: a.browserFlags || [],
496
532
  profileDir: a.profileDir || "",
497
533
  sessionTimeout: parseInt(a.sessionTimeout) || 3600,
@@ -499,9 +535,14 @@ async function main() {
499
535
  idleTimeout: parseInt(a.idleTimeout) || 60000,
500
536
  maxActionsPerMinute: parseInt(a.maxActionsPerMinute) || 60,
501
537
  actionabilityTimeout: parseInt(a.actionabilityTimeout) || 500,
538
+ refCacheTtlMs: parseInt(a.refCacheTtlMs) || 30000,
502
539
  telemetry: a.telemetry || false,
503
540
  githubCacheTtlMs: parseInt(a.githubCacheTtlMs) || 1800000,
504
541
  downloadDir: a.downloadDir || "",
542
+ pdfDir: a.pdfDir || "",
543
+ snapshotDir: a.snapshotDir || "",
544
+ recordingDir: a.recordingDir || "",
545
+ designDir: a.designDir || "",
505
546
  proxy: typeof a.proxy === "string" && a.proxy.trim() ? a.proxy.trim() : undefined,
506
547
  policies: a.policies || [],
507
548
  });
@@ -610,7 +651,40 @@ async function main() {
610
651
  mcpConfigured = true;
611
652
  }
612
653
  }
613
- // ── PHASE 5: SUMMARY ───────────────────────────────────────────────────────
654
+ // ── PHASE 5: AGENT SKILLS ────────────────────────────────────────────────────
655
+ console.log(boxen(pc.blue("PHASE 5: AGENT SKILLS"), { padding: 1, borderStyle: 'round', borderColor: 'blue' }));
656
+ let skillsInstalled = false;
657
+ const installSkillsNow = await p.confirm({
658
+ message: "Install or update Weavetab agent skills? (domain guides for your AI agent)",
659
+ initialValue: true
660
+ });
661
+ if (!p.isCancel(installSkillsNow) && installSkillsNow) {
662
+ const agentFramework = await p.select({
663
+ message: "Select your target AI agent framework:",
664
+ options: [
665
+ { value: ".agent", label: "Antigravity", hint: ".agent/skills/<domain>/SKILL.md" },
666
+ { value: ".cursor", label: "Cursor IDE", hint: ".cursor/rules/weavetab-<domain>.mdc" },
667
+ { value: ".clinerules", label: "Cline", hint: ".clinerules" },
668
+ { value: ".windsurf", label: "Windsurf", hint: ".windsurf/rules/" },
669
+ { value: ".openclaw", label: "OpenClaw", hint: ".openclaw/skills/" },
670
+ { value: ".roocode", label: "RooCode", hint: ".roocode/rules/" },
671
+ { value: "generic", label: "Raw Markdown", hint: "weavetab-skills/ directory" },
672
+ ]
673
+ });
674
+ if (!p.isCancel(agentFramework)) {
675
+ const { execSync: exec } = await import("node:child_process");
676
+ p.note(`${pc.dim("Installing skills for")} ${pc.cyan(agentFramework)} ${pc.dim("via")} ${pc.cyan("npx @weavetab/skills@latest")}...`, "SKILLS INSTALLER");
677
+ console.log();
678
+ try {
679
+ exec(`npx -y @weavetab/skills@latest --framework ${agentFramework}`, { stdio: "inherit" });
680
+ skillsInstalled = true;
681
+ }
682
+ catch {
683
+ console.log(pc.yellow(`[WARN] Skills install failed — run 'npx @weavetab/skills@latest -f ${agentFramework}' manually`));
684
+ }
685
+ }
686
+ }
687
+ // ── PHASE 6: SUMMARY ───────────────────────────────────────────────────────
614
688
  console.log(boxen(pc.green("CONFIGURATION COMPLETE"), { padding: 1, borderStyle: 'round', borderColor: 'green' }));
615
689
  const summary = [
616
690
  `${pc.dim("Browser:")} ${a.browser}`,
@@ -620,6 +694,7 @@ async function main() {
620
694
  `${pc.dim("Max tabs:")} ${partialConfig.maxTabs}`,
621
695
  `${pc.dim("Config location:")} ~/.weavetab/config.json`,
622
696
  `${pc.dim("MCP Config:")} ${mcpConfigured ? pc.green("[OK] Configured") : pc.yellow("Pending")}`,
697
+ `${pc.dim("Skills:")} ${skillsInstalled ? pc.green("[OK] Installed") : pc.dim("Skipped")}`,
623
698
  ];
624
699
  if (a.block?.length)
625
700
  summary.push(`${pc.dim("Blocked:")} ${a.block.join(", ")}`);
@@ -970,7 +1045,7 @@ async function main() {
970
1045
  const open = (await import("open")).default;
971
1046
  const config = await loadConfig();
972
1047
  const _require = createRequire(import.meta.url);
973
- const version = _require("../package.json").version || "2.5.0";
1048
+ const version = _require("../package.json").version || WEAVETAB_VERSION;
974
1049
  console.clear();
975
1050
  await checkForUpdates();
976
1051
  // Config resolution info
@@ -1001,7 +1076,7 @@ async function main() {
1001
1076
  console.log(pc.bold("LINKS"));
1002
1077
  console.log(` ${pc.cyan("[G]")} GitHub ${pc.dim("github.com/Weavetab")}`);
1003
1078
  console.log(` ${pc.cyan("[N]")} NPM ${pc.dim("npmjs.com/package/Weavetab")}`);
1004
- console.log(` ${pc.cyan("[W]")} Website ${pc.dim("weavetab.pages.dev")}`);
1079
+ console.log(` ${pc.cyan("[W]")} Website ${pc.dim("weavetab.dev")}`);
1005
1080
  console.log();
1006
1081
  console.log(pc.dim("Awaiting command..."));
1007
1082
  process.stdin.setRawMode(true);
@@ -1063,10 +1138,10 @@ async function main() {
1063
1138
  runMainUI();
1064
1139
  }
1065
1140
  if (k === "g") {
1066
- await open("https://github.com/Weavetab");
1141
+ await open("https://github.com/weavetab");
1067
1142
  }
1068
1143
  if (k === "n") {
1069
- await open("https://npmjs.com/package/Weavetab");
1144
+ await open("https://www.npmjs.com/package/@weavetab/mcp");
1070
1145
  }
1071
1146
  if (k === "w") {
1072
1147
  await open("https://github.com/weavetab/mcp");
@@ -1076,7 +1151,7 @@ async function main() {
1076
1151
  }
1077
1152
  function runHelp() {
1078
1153
  const _require = createRequire(import.meta.url);
1079
- const version = _require("../package.json").version || "2.5.0";
1154
+ const version = _require("../package.json").version || WEAVETAB_VERSION;
1080
1155
  console.clear();
1081
1156
  console.log(boxen(pc.cyan(`Weavetab v${version}`), { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
1082
1157
  console.log(pc.dim("Production-grade MCP server for Chrome DevTools Protocol"));
@@ -1087,12 +1162,17 @@ async function main() {
1087
1162
  console.log(pc.bold("COMMANDS"));
1088
1163
  console.log(` ${pc.cyan("plugin")} Manage Weavetab plugins (add, list, remove, search, browse, verify)`);
1089
1164
  console.log(` ${pc.cyan("config")} Launch the interactive configuration wizard`);
1165
+ console.log(` ${pc.cyan("skills")} Install or update AI agent skills (@weavetab/skills)`);
1090
1166
  console.log(` ${pc.cyan("view")} Display the current active configuration`);
1091
1167
  console.log(` ${pc.cyan("reset")} Purge browser profiles, lockfiles, and orphan processes`);
1092
1168
  console.log(` ${pc.cyan("secrets")} Manage blind-injected credentials (set, list, rm)`);
1093
1169
  console.log(` ${pc.cyan("reload-ext")} Send a reload signal to the browser extension`);
1094
1170
  console.log(` ${pc.cyan("help")} Show this help message`);
1095
1171
  console.log();
1172
+ console.log(pc.bold("AGENT SKILLS (@weavetab/skills)"));
1173
+ console.log(` ${pc.dim("Install/update skills:")} ${pc.cyan("npx -y @weavetab/skills@latest")}`);
1174
+ console.log(` ${pc.dim("Via CLI:")} ${pc.cyan("weavetab skills [options]")}`);
1175
+ console.log();
1096
1176
  console.log(pc.bold("PLUGIN COMMANDS (User)"));
1097
1177
  console.log(` ${pc.cyan("weavetab plugin add <pkg>")} Install a plugin (resolves official @weavetab/plugin- & community)`);
1098
1178
  console.log(` ${pc.cyan("weavetab plugin browse")} Interactive terminal explorer to browse & 1-click install`);
@@ -1116,8 +1196,8 @@ async function main() {
1116
1196
  console.log(` ${pc.cyan("WT_AGENT_ID")} Agent identifier (auto-generated if unset)`);
1117
1197
  console.log();
1118
1198
  console.log(pc.bold("LINKS"));
1119
- console.log(` ${pc.cyan("GitHub:")} ${pc.dim("https://github.com/Weavetab")}`);
1120
- console.log(` ${pc.cyan("npm:")} ${pc.dim("https://npmjs.com/package/Weavetab")}`);
1199
+ console.log(` ${pc.cyan("GitHub:")} ${pc.dim("https://github.com/weavetab")}`);
1200
+ console.log(` ${pc.cyan("npm:")} ${pc.dim("https://www.npmjs.com/package/@weavetab/mcp")}`);
1121
1201
  console.log(` ${pc.cyan("Website:")} ${pc.dim("https://github.com/weavetab/mcp")}`);
1122
1202
  console.log();
1123
1203
  }
@@ -1235,7 +1315,7 @@ async function runSecretsCommand(args) {
1235
1315
  }
1236
1316
  }
1237
1317
  await secretStore.setSecret(key, value, domains);
1238
- console.log(pc.green(`[OK] Secret "${key}" saved successfully.`));
1318
+ console.log(pc.green(`[OK] Secret "${key}" saved.`));
1239
1319
  return;
1240
1320
  }
1241
1321
  console.log(pc.red(`[ERROR] Unknown secrets command: ${subcmd}`));
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Weavetab — intelligence/marks.ts
3
+ * Visual grounding mark cache.
4
+ *
5
+ * When browser_map runs with visual: true/auto, numbered SoM badges are
6
+ * injected over the page, a screenshot is taken, and each badge's position
7
+ * and optional DOM ref are stored here. Interaction tools (browser_click,
8
+ * browser_pointer, etc.) can then resolve a { mark: N } argument directly
9
+ * to pixel coordinates without any further DOM walk.
10
+ *
11
+ * Weavetab by fy2ne
12
+ */
13
+ export interface MarkEntry {
14
+ /** Center X coordinate (viewport-relative pixels). */
15
+ x: number;
16
+ /** Center Y coordinate (viewport-relative pixels). */
17
+ y: number;
18
+ /** Width of the element bounding box. */
19
+ width: number;
20
+ /** Height of the element bounding box. */
21
+ height: number;
22
+ /** Volatile ref ID (w:NN) if the element is DOM-backed. Undefined for canvas/visual-only regions. */
23
+ ref?: string;
24
+ /** Visible text or aria-label, if available. */
25
+ label?: string;
26
+ /** Element type hint. */
27
+ type?: "button" | "input" | "link" | "select" | "canvas_region" | "unknown";
28
+ }
29
+ /** Write a full set of marks for a tab. Replaces any previous marks. */
30
+ export declare function marksSet(targetId: string, marks: Map<number, MarkEntry>): void;
31
+ /** Look up a single mark for a tab. Returns null if not found. */
32
+ export declare function marksGet(targetId: string, mark: number): MarkEntry | null;
33
+ /** Clear all marks for a tab (called on navigation). */
34
+ export declare function marksInvalidate(targetId: string): void;
35
+ /** Return all marks for a tab (used for debugging / list output). */
36
+ export declare function marksGetAll(targetId: string): Map<number, MarkEntry>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Weavetab — intelligence/marks.ts
3
+ * Visual grounding mark cache.
4
+ *
5
+ * When browser_map runs with visual: true/auto, numbered SoM badges are
6
+ * injected over the page, a screenshot is taken, and each badge's position
7
+ * and optional DOM ref are stored here. Interaction tools (browser_click,
8
+ * browser_pointer, etc.) can then resolve a { mark: N } argument directly
9
+ * to pixel coordinates without any further DOM walk.
10
+ *
11
+ * Weavetab by fy2ne
12
+ */
13
+ /** Per-tab: Map<targetId, Map<markNumber, MarkEntry>> */
14
+ const store = new Map();
15
+ /** Write a full set of marks for a tab. Replaces any previous marks. */
16
+ export function marksSet(targetId, marks) {
17
+ store.set(targetId, marks);
18
+ }
19
+ /** Look up a single mark for a tab. Returns null if not found. */
20
+ export function marksGet(targetId, mark) {
21
+ return store.get(targetId)?.get(mark) ?? null;
22
+ }
23
+ /** Clear all marks for a tab (called on navigation). */
24
+ export function marksInvalidate(targetId) {
25
+ store.delete(targetId);
26
+ }
27
+ /** Return all marks for a tab (used for debugging / list output). */
28
+ export function marksGetAll(targetId) {
29
+ return store.get(targetId) ?? new Map();
30
+ }
@@ -0,0 +1,118 @@
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
+ export interface WorkflowStep {
16
+ /** MCP tool name, e.g. "browser_click", "browser_fill", "browser_navigate" */
17
+ tool: string;
18
+ /** Primary selector or URL target */
19
+ target?: string;
20
+ /** Optional value (text typed, option selected, etc.) */
21
+ value?: string;
22
+ /** Any extra args forwarded verbatim to browser_burst replay */
23
+ extra?: Record<string, unknown>;
24
+ }
25
+ export interface WorkflowPattern {
26
+ /** Caller-assigned name in snake_case, e.g. "login_flow", "pr_review" */
27
+ name: string;
28
+ /** Compiled, stable steps ready for browser_burst replay */
29
+ steps: WorkflowStep[];
30
+ /** Optional CSS selector / URL fragment that confirms success */
31
+ success_indicator?: string;
32
+ /** URL path or pattern where this workflow starts, e.g. "/pull/:id/files" */
33
+ entry?: string;
34
+ /** Exponentially-weighted moving average of duration in ms */
35
+ avg_duration_ms?: number;
36
+ /** 0.0 – 1.0 reliability. Degrades on failures, climbs on successes. */
37
+ reliability: number;
38
+ /** Consecutive failure counter — 3 strikes triggers re-learn flag */
39
+ strikes: number;
40
+ /** ISO timestamp of last successful verified run */
41
+ last_verified: string;
42
+ /** Total times this pattern was executed */
43
+ total_executions: number;
44
+ /** Times the pattern completed without errors */
45
+ successful_executions: number;
46
+ }
47
+ export interface SiteQuirks {
48
+ cookie_banner?: {
49
+ selector: string;
50
+ action: string;
51
+ appears: "first_visit" | "always" | "random";
52
+ };
53
+ rate_limit?: {
54
+ threshold?: string;
55
+ recovery?: string;
56
+ };
57
+ modal_popups?: Array<{
58
+ trigger?: string;
59
+ dismiss_selector: string;
60
+ }>;
61
+ [key: string]: unknown;
62
+ }
63
+ export interface SiteProfile {
64
+ /** Full origin, e.g. "https://github.com" */
65
+ origin: string;
66
+ /** Detected JS framework: react, vue, angular, next, nuxt, svelte, etc. */
67
+ framework?: string;
68
+ /** True if the site uses Shadow DOM components */
69
+ shadowDom?: boolean;
70
+ /** How often this site presents CAPTCHA challenges */
71
+ captcha_frequency?: "none" | "rare" | "moderate" | "frequent";
72
+ /** Known site-level quirks to handle automatically */
73
+ quirks: SiteQuirks;
74
+ /** Named, compiled workflow patterns indexed by name */
75
+ patterns: Record<string, WorkflowPattern>;
76
+ /** ISO timestamp of last profile write */
77
+ updatedAt: string;
78
+ /** How many times this origin has been visited in automated sessions */
79
+ visitCount: number;
80
+ }
81
+ export declare function clearSiteProfileCache(): void;
82
+ /**
83
+ * Load a site profile from disk. Returns null if the site has never been profiled.
84
+ * Hits in-process cache first — no redundant disk reads within a session.
85
+ */
86
+ export declare function getSiteProfile(origin: string): Promise<SiteProfile | null>;
87
+ /**
88
+ * Persist a site profile. Always deep-merges into existing data on disk — never
89
+ * blindly overwrites — so concurrent tool calls don't clobber each other.
90
+ */
91
+ export declare function saveSiteProfile(profile: SiteProfile): Promise<void>;
92
+ /**
93
+ * Learn or update a named workflow pattern for a given origin.
94
+ * - Duplicate name = merge/update, never duplicate file.
95
+ * - Volatile selectors in steps are dropped to keep patterns stable.
96
+ * - Anti-spam: skips disk write when content is identical to existing.
97
+ */
98
+ export declare function learnPattern(origin: string, name: string, incoming: Partial<WorkflowPattern>): Promise<WorkflowPattern>;
99
+ /**
100
+ * Record the outcome of executing a named pattern.
101
+ * Updates reliability via EWMA (α=0.15) and tracks consecutive strikes.
102
+ * 3 strikes → reliability will naturally fall below 0.4, agent should re-explore.
103
+ */
104
+ export declare function recordPatternExecution(origin: string, patternName: string, success: boolean, durationMs?: number): Promise<WorkflowPattern | null>;
105
+ /**
106
+ * Record or update a site quirk (cookie banner, rate limit, modal popup, etc.)
107
+ * Only writes if the stored data differs from incoming — prevents spam writes.
108
+ */
109
+ export declare function recordQuirk(origin: string, quirkKey: string, quirkData: unknown): Promise<void>;
110
+ /**
111
+ * Returns the reliability score (0–1) of a named pattern, or -1 if unknown.
112
+ */
113
+ export declare function getPatternReliability(origin: string, patternName: string): Promise<number>;
114
+ /**
115
+ * Formats a compact site profile hint string for agent system prompt injection.
116
+ * Called at session start when navigating to a known origin.
117
+ */
118
+ export declare function formatSiteProfileHint(profile: SiteProfile): string;