@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
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;
@@ -81,6 +98,32 @@ function printBootBanner(port) {
81
98
  async function main() {
82
99
  assertNotRoot();
83
100
  const args = process.argv.slice(2);
101
+ // Global flags: --version always works; --ws starts the WebSocket daemon.
102
+ if (args.includes("--version") || args.includes("-v")) {
103
+ const _v = createRequire(import.meta.url);
104
+ const ver = _v("../package.json").version || WEAVETAB_VERSION;
105
+ console.log(`@weavetab/mcp v${ver}`);
106
+ process.exit(0);
107
+ }
108
+ if (args.includes("--ws")) {
109
+ let wsPort = 3000;
110
+ const pi = args.findIndex((a) => a === "--port");
111
+ const eq = args.find((a) => a.startsWith("--port="));
112
+ const rawPort = pi >= 0 ? args[pi + 1] : eq ? eq.slice("--port=".length) : undefined;
113
+ if (rawPort !== undefined) {
114
+ const parsed = parseInt(rawPort, 10);
115
+ if (isNaN(parsed) || parsed < 1 || parsed > 65535) {
116
+ console.error(`[Weavetab] Invalid --port value: "${rawPort}" (1-65535).`);
117
+ process.exit(1);
118
+ }
119
+ wsPort = parsed;
120
+ }
121
+ const config = await loadConfig();
122
+ global.__wt_is_server = true;
123
+ await printBootBanner(wsPort);
124
+ await startServer(config, "ws", wsPort);
125
+ return;
126
+ }
84
127
  // If NOT in a TTY environment (e.g. spawned by Claude Code as MCP server)
85
128
  if (!isInteractive && args.length === 0) {
86
129
  // Singleton guard — exit immediately if another MCP server is alive.
@@ -134,6 +177,17 @@ async function main() {
134
177
  await runPluginCli(args.slice(1));
135
178
  process.exit(0);
136
179
  }
180
+ if (cmd === "skills") {
181
+ const { execSync: exec } = await import("node:child_process");
182
+ const subArgs = args.slice(1).join(" ");
183
+ try {
184
+ exec(`npx -y @weavetab/skills@latest ${subArgs}`.trim(), { stdio: "inherit" });
185
+ }
186
+ catch {
187
+ process.exit(1);
188
+ }
189
+ process.exit(0);
190
+ }
137
191
  if (cmd === "init" || cmd === "create" || cmd === "build" || cmd === "manifest") {
138
192
  console.log(pc.yellow(`\n[Weavetab] Plugin authoring commands are part of the developer SDK (@weavetab/sdk).`));
139
193
  console.log(pc.dim("To scaffold a new plugin: ") + pc.cyan("npx -y @weavetab/sdk init <name>"));
@@ -335,6 +389,7 @@ async function main() {
335
389
  S.sl("Role *", {
336
390
  initialValue: "admin", options: [
337
391
  { value: "admin", label: "Admin", hint: "Full access to all tools" },
392
+ { value: "operator", label: "Operator", hint: "Full access, standard agent role" },
338
393
  { value: "viewer", label: "Viewer", hint: "Read-only access (map, find, scrape, console)" },
339
394
  { value: "automation", label: "Automation", hint: "CI/CD mode (burst, plan, wait, map)" },
340
395
  ]
@@ -406,6 +461,7 @@ async function main() {
406
461
  }, "browserType"),
407
462
  S.cf("Enable Weavetab browser extension?", "extension", true),
408
463
  S.cf("Persist cookies across sessions?", "cookies", false),
464
+ S.cf("Sync browser data across profiles?", "syncDataAcrossBrowsers", false),
409
465
  S.tx("Extra browser flags (space-separated)", "browserFlagsRaw", ""),
410
466
  S.tx("Custom browser profile directory", "profileDir", ""),
411
467
  ])) === "back")
@@ -427,6 +483,8 @@ async function main() {
427
483
  return "Positive integer."; }),
428
484
  S.tx("Actionability timeout (ms)", "actionabilityTimeout", "500", (v) => { const n = parseInt(v ?? ""); if (isNaN(n) || n < 100)
429
485
  return "Min 100 ms."; }),
486
+ S.tx("Ref cache TTL (ms) — stale element handle expiry", "refCacheTtlMs", "30000", (v) => { const n = parseInt(v ?? ""); if (isNaN(n) || n < 1000)
487
+ return "Min 1000 ms."; }),
430
488
  ])) === "back")
431
489
  process.exit(0);
432
490
  }
@@ -445,6 +503,10 @@ async function main() {
445
503
  console.log(boxen(pc.cyan("SECTION D: STORAGE & PROXY"), { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
446
504
  if ((await run([
447
505
  S.tx("Download directory", "downloadDir", ""),
506
+ S.tx("PDF output directory", "pdfDir", ""),
507
+ S.tx("Snapshot directory (screenshots)", "snapshotDir", ""),
508
+ S.tx("Recording output directory", "recordingDir", ""),
509
+ S.tx("Design extraction directory", "designDir", ""),
448
510
  S.tx("Proxy URL (or $WT_PROXY_URL)", "proxy", ""),
449
511
  ])) === "back")
450
512
  process.exit(0);
@@ -492,6 +554,7 @@ async function main() {
492
554
  browserType: a.browserType || "chromium",
493
555
  extension: a.extension !== undefined ? a.extension : true,
494
556
  cookies: a.cookies || false,
557
+ syncDataAcrossBrowsers: a.syncDataAcrossBrowsers || false,
495
558
  browserFlags: a.browserFlags || [],
496
559
  profileDir: a.profileDir || "",
497
560
  sessionTimeout: parseInt(a.sessionTimeout) || 3600,
@@ -499,9 +562,14 @@ async function main() {
499
562
  idleTimeout: parseInt(a.idleTimeout) || 60000,
500
563
  maxActionsPerMinute: parseInt(a.maxActionsPerMinute) || 60,
501
564
  actionabilityTimeout: parseInt(a.actionabilityTimeout) || 500,
565
+ refCacheTtlMs: parseInt(a.refCacheTtlMs) || 30000,
502
566
  telemetry: a.telemetry || false,
503
567
  githubCacheTtlMs: parseInt(a.githubCacheTtlMs) || 1800000,
504
568
  downloadDir: a.downloadDir || "",
569
+ pdfDir: a.pdfDir || "",
570
+ snapshotDir: a.snapshotDir || "",
571
+ recordingDir: a.recordingDir || "",
572
+ designDir: a.designDir || "",
505
573
  proxy: typeof a.proxy === "string" && a.proxy.trim() ? a.proxy.trim() : undefined,
506
574
  policies: a.policies || [],
507
575
  });
@@ -610,7 +678,40 @@ async function main() {
610
678
  mcpConfigured = true;
611
679
  }
612
680
  }
613
- // ── PHASE 5: SUMMARY ───────────────────────────────────────────────────────
681
+ // ── PHASE 5: AGENT SKILLS ────────────────────────────────────────────────────
682
+ console.log(boxen(pc.blue("PHASE 5: AGENT SKILLS"), { padding: 1, borderStyle: 'round', borderColor: 'blue' }));
683
+ let skillsInstalled = false;
684
+ const installSkillsNow = await p.confirm({
685
+ message: "Install or update Weavetab agent skills? (domain guides for your AI agent)",
686
+ initialValue: true
687
+ });
688
+ if (!p.isCancel(installSkillsNow) && installSkillsNow) {
689
+ const agentFramework = await p.select({
690
+ message: "Select your target AI agent framework:",
691
+ options: [
692
+ { value: ".agent", label: "Antigravity", hint: ".agent/skills/<domain>/SKILL.md" },
693
+ { value: ".cursor", label: "Cursor IDE", hint: ".cursor/rules/weavetab-<domain>.mdc" },
694
+ { value: ".clinerules", label: "Cline", hint: ".clinerules" },
695
+ { value: ".windsurf", label: "Windsurf", hint: ".windsurf/rules/" },
696
+ { value: ".openclaw", label: "OpenClaw", hint: ".openclaw/skills/" },
697
+ { value: ".roocode", label: "RooCode", hint: ".roocode/rules/" },
698
+ { value: "generic", label: "Raw Markdown", hint: "weavetab-skills/ directory" },
699
+ ]
700
+ });
701
+ if (!p.isCancel(agentFramework)) {
702
+ const { execSync: exec } = await import("node:child_process");
703
+ p.note(`${pc.dim("Installing skills for")} ${pc.cyan(agentFramework)} ${pc.dim("via")} ${pc.cyan("npx @weavetab/skills@latest")}...`, "SKILLS INSTALLER");
704
+ console.log();
705
+ try {
706
+ exec(`npx -y @weavetab/skills@latest --framework ${agentFramework}`, { stdio: "inherit" });
707
+ skillsInstalled = true;
708
+ }
709
+ catch {
710
+ console.log(pc.yellow(`[WARN] Skills install failed — run 'npx @weavetab/skills@latest -f ${agentFramework}' manually`));
711
+ }
712
+ }
713
+ }
714
+ // ── PHASE 6: SUMMARY ───────────────────────────────────────────────────────
614
715
  console.log(boxen(pc.green("CONFIGURATION COMPLETE"), { padding: 1, borderStyle: 'round', borderColor: 'green' }));
615
716
  const summary = [
616
717
  `${pc.dim("Browser:")} ${a.browser}`,
@@ -620,6 +721,7 @@ async function main() {
620
721
  `${pc.dim("Max tabs:")} ${partialConfig.maxTabs}`,
621
722
  `${pc.dim("Config location:")} ~/.weavetab/config.json`,
622
723
  `${pc.dim("MCP Config:")} ${mcpConfigured ? pc.green("[OK] Configured") : pc.yellow("Pending")}`,
724
+ `${pc.dim("Skills:")} ${skillsInstalled ? pc.green("[OK] Installed") : pc.dim("Skipped")}`,
623
725
  ];
624
726
  if (a.block?.length)
625
727
  summary.push(`${pc.dim("Blocked:")} ${a.block.join(", ")}`);
@@ -627,7 +729,7 @@ async function main() {
627
729
  summary.push(`${pc.dim("Allowed:")} ${a.allow.join(", ")}`);
628
730
  p.note(summary.join("\n"), "SUMMARY");
629
731
  if (!mcpConfigured) {
630
- console.log(pc.dim("\nTo configure MCP manually, run: weavetab config-mcp"));
732
+ console.log(pc.dim("\nTo configure MCP manually, run: weavetab config"));
631
733
  }
632
734
  p.outro(`${pc.green("Weavetab is ready!")} ${pc.dim("Run")} ${pc.cyan("weavetab help")} ${pc.dim("to see available commands.")}`);
633
735
  }
@@ -970,7 +1072,7 @@ async function main() {
970
1072
  const open = (await import("open")).default;
971
1073
  const config = await loadConfig();
972
1074
  const _require = createRequire(import.meta.url);
973
- const version = _require("../package.json").version || "2.5.0";
1075
+ const version = _require("../package.json").version || WEAVETAB_VERSION;
974
1076
  console.clear();
975
1077
  await checkForUpdates();
976
1078
  // Config resolution info
@@ -1001,7 +1103,7 @@ async function main() {
1001
1103
  console.log(pc.bold("LINKS"));
1002
1104
  console.log(` ${pc.cyan("[G]")} GitHub ${pc.dim("github.com/Weavetab")}`);
1003
1105
  console.log(` ${pc.cyan("[N]")} NPM ${pc.dim("npmjs.com/package/Weavetab")}`);
1004
- console.log(` ${pc.cyan("[W]")} Website ${pc.dim("weavetab.pages.dev")}`);
1106
+ console.log(` ${pc.cyan("[W]")} Website ${pc.dim("weavetab.dev")}`);
1005
1107
  console.log();
1006
1108
  console.log(pc.dim("Awaiting command..."));
1007
1109
  process.stdin.setRawMode(true);
@@ -1063,10 +1165,10 @@ async function main() {
1063
1165
  runMainUI();
1064
1166
  }
1065
1167
  if (k === "g") {
1066
- await open("https://github.com/Weavetab");
1168
+ await open("https://github.com/weavetab");
1067
1169
  }
1068
1170
  if (k === "n") {
1069
- await open("https://npmjs.com/package/Weavetab");
1171
+ await open("https://www.npmjs.com/package/@weavetab/mcp");
1070
1172
  }
1071
1173
  if (k === "w") {
1072
1174
  await open("https://github.com/weavetab/mcp");
@@ -1076,7 +1178,7 @@ async function main() {
1076
1178
  }
1077
1179
  function runHelp() {
1078
1180
  const _require = createRequire(import.meta.url);
1079
- const version = _require("../package.json").version || "2.5.0";
1181
+ const version = _require("../package.json").version || WEAVETAB_VERSION;
1080
1182
  console.clear();
1081
1183
  console.log(boxen(pc.cyan(`Weavetab v${version}`), { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
1082
1184
  console.log(pc.dim("Production-grade MCP server for Chrome DevTools Protocol"));
@@ -1087,14 +1189,21 @@ async function main() {
1087
1189
  console.log(pc.bold("COMMANDS"));
1088
1190
  console.log(` ${pc.cyan("plugin")} Manage Weavetab plugins (add, list, remove, search, browse, verify)`);
1089
1191
  console.log(` ${pc.cyan("config")} Launch the interactive configuration wizard`);
1192
+ console.log(` ${pc.cyan("skills")} Install or update AI agent skills (@weavetab/skills)`);
1090
1193
  console.log(` ${pc.cyan("view")} Display the current active configuration`);
1091
1194
  console.log(` ${pc.cyan("reset")} Purge browser profiles, lockfiles, and orphan processes`);
1092
- console.log(` ${pc.cyan("secrets")} Manage blind-injected credentials (set, list, rm)`);
1195
+ console.log(` ${pc.cyan("secrets")} Manage blind-injected credentials (set, list, rm, init)`);
1093
1196
  console.log(` ${pc.cyan("reload-ext")} Send a reload signal to the browser extension`);
1197
+ console.log(` ${pc.cyan("--ws")} Start the WebSocket daemon (default port 3000, override with --port)`);
1198
+ console.log(` ${pc.cyan("--version")} Print version and exit`);
1094
1199
  console.log(` ${pc.cyan("help")} Show this help message`);
1095
1200
  console.log();
1201
+ console.log(pc.bold("AGENT SKILLS (@weavetab/skills)"));
1202
+ console.log(` ${pc.dim("Install/update skills:")} ${pc.cyan("npx -y @weavetab/skills@latest")}`);
1203
+ console.log(` ${pc.dim("Via CLI:")} ${pc.cyan("weavetab skills [options]")}`);
1204
+ console.log();
1096
1205
  console.log(pc.bold("PLUGIN COMMANDS (User)"));
1097
- console.log(` ${pc.cyan("weavetab plugin add <pkg>")} Install a plugin (resolves official @weavetab/plugin- & community)`);
1206
+ console.log(` ${pc.cyan("weavetab plugin add <pkg>")} Install a plugin from npm (or a local path: ./my-plugin)`);
1098
1207
  console.log(` ${pc.cyan("weavetab plugin browse")} Interactive terminal explorer to browse & 1-click install`);
1099
1208
  console.log(` ${pc.cyan("weavetab plugin search <query>")} Search plugins across registry & npm`);
1100
1209
  console.log(` ${pc.cyan("weavetab plugin list")} List all installed Weavetab plugins and tools`);
@@ -1116,9 +1225,9 @@ async function main() {
1116
1225
  console.log(` ${pc.cyan("WT_AGENT_ID")} Agent identifier (auto-generated if unset)`);
1117
1226
  console.log();
1118
1227
  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")}`);
1121
- console.log(` ${pc.cyan("Website:")} ${pc.dim("https://github.com/weavetab/mcp")}`);
1228
+ console.log(` ${pc.cyan("GitHub:")} ${pc.dim("https://github.com/weavetab")}`);
1229
+ console.log(` ${pc.cyan("npm:")} ${pc.dim("https://www.npmjs.com/package/@weavetab/mcp")}`);
1230
+ console.log(` ${pc.cyan("Website:")} ${pc.dim("https://weavetab.dev")}`);
1122
1231
  console.log();
1123
1232
  }
1124
1233
  }
@@ -1157,10 +1266,17 @@ async function runSecretsCommand(args) {
1157
1266
  const { secretStore } = await import("./security/secrets.js");
1158
1267
  const p = await import("@clack/prompts");
1159
1268
  if (args.length === 0) {
1160
- console.log(pc.red("[ERROR] Usage: weavetab secrets <set|list|rm> [key]"));
1269
+ console.log(pc.red("[ERROR] Usage: weavetab secrets <set|list|rm|init> [key]"));
1161
1270
  process.exit(1);
1162
1271
  }
1163
1272
  const subcmd = args[0].toLowerCase();
1273
+ if (subcmd === "init") {
1274
+ const { initProjectSecrets } = await import("./security/secrets.js");
1275
+ const filePath = initProjectSecrets();
1276
+ console.log(pc.green(`[OK] Project secrets initialized: ${filePath}`));
1277
+ console.log(pc.dim("Keys in this file take precedence over ~/.weavetab/secrets.json when Weavetab runs from this directory."));
1278
+ return;
1279
+ }
1164
1280
  if (subcmd === "list") {
1165
1281
  const list = await secretStore.listSecrets();
1166
1282
  console.log(boxen(pc.cyan("STORED SECRETS"), { padding: 1, borderStyle: 'round', borderColor: 'cyan' }));
@@ -1235,10 +1351,10 @@ async function runSecretsCommand(args) {
1235
1351
  }
1236
1352
  }
1237
1353
  await secretStore.setSecret(key, value, domains);
1238
- console.log(pc.green(`[OK] Secret "${key}" saved successfully.`));
1354
+ console.log(pc.green(`[OK] Secret "${key}" saved.`));
1239
1355
  return;
1240
1356
  }
1241
1357
  console.log(pc.red(`[ERROR] Unknown secrets command: ${subcmd}`));
1242
- console.log(pc.red("Usage: weavetab secrets <set|list|rm> [key]"));
1358
+ console.log(pc.red("Usage: weavetab secrets <set|list|rm|init> [key]"));
1243
1359
  process.exit(1);
1244
1360
  }
@@ -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;