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

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 (89) hide show
  1. package/AGENTS.md +1 -0
  2. package/LICENSE +2 -2
  3. package/README.md +208 -43
  4. package/SECURITY.md +3 -3
  5. package/TROUBLESHOOTING.md +1 -1
  6. package/dist/cdp/bridge.d.ts +10 -0
  7. package/dist/cdp/bridge.js +284 -78
  8. package/dist/cdp/connector.d.ts +5 -3
  9. package/dist/cdp/connector.js +188 -71
  10. package/dist/cdp/lock.d.ts +9 -6
  11. package/dist/cdp/lock.js +72 -59
  12. package/dist/cdp/omni_broker.d.ts +1 -0
  13. package/dist/cdp/omni_broker.js +12 -6
  14. package/dist/cdp/profiles.d.ts +10 -0
  15. package/dist/cdp/profiles.js +65 -0
  16. package/dist/cdp/walker.js +50 -0
  17. package/dist/cli/plugin.d.ts +0 -2
  18. package/dist/cli/plugin.js +31 -683
  19. package/dist/cli/updater.js +2 -2
  20. package/dist/config/loader.d.ts +25 -6
  21. package/dist/config/loader.js +133 -20
  22. package/dist/index.js +48 -52
  23. package/dist/overlay/ghost.js +2 -2
  24. package/dist/overlay/injector.js +1 -3
  25. package/dist/plugin/extension_bridge.d.ts +40 -0
  26. package/dist/plugin/extension_bridge.js +158 -0
  27. package/dist/plugin/interface.d.ts +78 -16
  28. package/dist/plugin/loader.d.ts +4 -0
  29. package/dist/plugin/loader.js +178 -57
  30. package/dist/plugin/registry.js +11 -1
  31. package/dist/plugin/storage.d.ts +51 -0
  32. package/dist/plugin/storage.js +164 -0
  33. package/dist/server.js +213 -121
  34. package/dist/state/session.d.ts +2 -2
  35. package/dist/state/session.js +33 -13
  36. package/dist/tools/browser_detect.d.ts +2 -1
  37. package/dist/tools/browser_detect.js +6 -3
  38. package/dist/tools/burst.d.ts +1 -0
  39. package/dist/tools/burst.js +4 -6
  40. package/dist/tools/click.js +23 -28
  41. package/dist/tools/clipboard.js +31 -24
  42. package/dist/tools/navigate.d.ts +1 -1
  43. package/dist/tools/navigate.js +28 -10
  44. package/dist/tools/tabs.d.ts +10 -10
  45. package/dist/tools/tabs.js +47 -39
  46. package/dist/tools/type.js +2 -2
  47. package/docs/DOCUMENTATION.md +63 -6
  48. package/docs/architecture/blind-injection.md +20 -0
  49. package/docs/architecture/dual-injection.md +32 -0
  50. package/docs/architecture/overview.md +49 -0
  51. package/docs/architecture/security.md +35 -0
  52. package/docs/architecture/transport.md +37 -0
  53. package/docs/captcha-stealth/captcha-solver.md +75 -0
  54. package/docs/captcha-stealth/stealth-physics.md +60 -0
  55. package/docs/cli/cli-commands.md +44 -0
  56. package/docs/cli/cli-flags.md +20 -0
  57. package/docs/cli/cli-introduction.md +20 -0
  58. package/docs/cli/cli-scripting.md +32 -0
  59. package/docs/cli/g-ide/ide-antigravity.md +24 -0
  60. package/docs/cli/g-ide/ide-claude-code.md +24 -0
  61. package/docs/cli/g-ide/ide-claude-desktop.md +32 -0
  62. package/docs/cli/g-ide/ide-cursor.md +31 -0
  63. package/docs/cli/g-ide/ide-generic.md +34 -0
  64. package/docs/cli/g-ide/ide-opencode.md +24 -0
  65. package/docs/cli/g-ide/ide-vscode-copilot.md +24 -0
  66. package/docs/cli/g-ide/ide-windsurf.md +24 -0
  67. package/docs/configuration/config-locations.md +24 -0
  68. package/docs/configuration/configuration.md +73 -0
  69. package/docs/configuration/env-variables.md +19 -0
  70. package/docs/configuration/folders.md +54 -0
  71. package/docs/desktop-automation/electron-apps.md +162 -0
  72. package/docs/get-started/installation.md +47 -0
  73. package/docs/get-started/introduction.md +60 -0
  74. package/docs/get-started/quickstart.md +54 -0
  75. package/docs/get-started/setup-wizard.md +26 -0
  76. package/docs/skills-ecosystem/skills-overview.md +35 -0
  77. package/docs/skills-ecosystem/skills-recipes.md +36 -0
  78. package/docs/tools/tools.md +293 -0
  79. package/docs/troubleshooting/trouble-browser.md +27 -0
  80. package/docs/troubleshooting/trouble-config.md +20 -0
  81. package/docs/troubleshooting/trouble-loop.md +31 -0
  82. package/ext-dist/content.js +0 -1
  83. package/mcp.json +8 -6
  84. package/package.json +11 -5
  85. package/server.json +3 -3
  86. package/docs/DEV_MODE.md +0 -68
  87. package/docs/PLUGINS.md +0 -538
  88. package/docs/TOOLS.md +0 -104
  89. package/docs/dev_plugin.md +0 -310
@@ -2,11 +2,18 @@ import * as p from "@clack/prompts";
2
2
  import pc from "picocolors";
3
3
  import boxen from "boxen";
4
4
  import ora from "ora";
5
- import fs from "node:fs/promises";
6
- import { existsSync } from "node:fs";
7
5
  import path from "node:path";
8
- import { pathToFileURL } from "node:url";
9
6
  import { spawn } from "node:child_process";
7
+ import { createRequire } from "node:module";
8
+ const _require = createRequire(import.meta.url);
9
+ function getVersion() {
10
+ try {
11
+ return _require("../../package.json").version || "2.5.0-beta.2";
12
+ }
13
+ catch {
14
+ return "2.5.0-beta.2";
15
+ }
16
+ }
10
17
  import { getVerifiedPackages, resolvePluginTrust, resolvePluginCandidates, REGISTRY_URL, } from "../plugin/registry.js";
11
18
  import { listInstalledPlugins, inspectInstalledPackage } from "../plugin/loader.js";
12
19
  // Helper to run child process safely
@@ -40,7 +47,7 @@ function runNpmCommand(cmdArgs, cwd = process.cwd()) {
40
47
  export async function runPluginAdd(inputName, args = []) {
41
48
  if (!inputName || inputName.startsWith("-")) {
42
49
  console.log(pc.red("[ERROR] Please provide a package name to install."));
43
- console.log(pc.dim("Usage: wt plugin add <packageName> [--official | --community] [--yes]"));
50
+ console.log(pc.dim("Usage: weavetab plugin add <packageName> [--official | --community] [--yes]"));
44
51
  return;
45
52
  }
46
53
  const isForce = args.includes("--yes") || args.includes("-y") || args.includes("--force");
@@ -210,7 +217,7 @@ export async function runPluginAdd(inputName, args = []) {
210
217
  console.log();
211
218
  console.log(boxen(`${pc.yellow("⚠️ NOTE: No 'weavetab.json' manifest was detected inside this package.")}\n` +
212
219
  pc.dim("Weavetab requires a valid weavetab.json manifest to automatically register tools.\n") +
213
- pc.dim(`If you are the author, run ${pc.cyan("wt plugin init")} in the package directory to generate one.`), { padding: 1, borderStyle: "round", borderColor: "yellow" }));
220
+ pc.dim(`If you are the author, build the plugin using the developer SDK: ${pc.cyan("npx @weavetab/sdk build")}`), { padding: 1, borderStyle: "round", borderColor: "yellow" }));
214
221
  console.log();
215
222
  }
216
223
  }
@@ -225,7 +232,7 @@ export async function runPluginList() {
225
232
  console.log();
226
233
  if (plugins.length === 0) {
227
234
  console.log(pc.dim("No Weavetab plugins found in the local node_modules directory."));
228
- console.log(pc.dim(`Install official or community plugins using: ${pc.cyan("wt plugin add <packageName>")}\n`));
235
+ console.log(pc.dim(`Install official or community plugins using: ${pc.cyan("weavetab plugin add <packageName>")}\n`));
229
236
  return;
230
237
  }
231
238
  console.log(pc.dim(`Found ${plugins.length} installed plugin(s):\n`));
@@ -269,7 +276,7 @@ export async function runPluginSearch(query) {
269
276
  const searchQuery = q ? `weavetab ${q}` : "weavetab plugin";
270
277
  const res = await fetch(`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(searchQuery)}&size=15`, {
271
278
  signal: AbortSignal.timeout(3500),
272
- headers: { "User-Agent": "Weavetab-CLI/2.5.0" },
279
+ headers: { "User-Agent": `Weavetab/${getVersion()}` },
273
280
  });
274
281
  if (res.ok) {
275
282
  const data = (await res.json());
@@ -301,14 +308,14 @@ export async function runPluginSearch(query) {
301
308
  console.log();
302
309
  if (results.length === 0) {
303
310
  console.log(pc.yellow(`No plugins matching "${q}" found.`));
304
- console.log(pc.dim(`Try browsing the registry or visit ${pc.cyan("https://weavetab.dev/plugins")}\n`));
311
+ console.log(pc.dim(`Try browsing the registry or visit ${pc.cyan("https://github.com/weavetab/mcp/plugins")}\n`));
305
312
  return;
306
313
  }
307
314
  console.log(pc.dim(`Found ${results.length} matching plugin(s):\n`));
308
315
  for (const item of results) {
309
316
  console.log(`${item.badge} ${pc.bold(pc.cyan(item.name))} ${pc.dim(`by ${item.author}`)}`);
310
317
  console.log(` ${pc.dim(item.description)}`);
311
- console.log(` ${pc.dim("Install:")} ${pc.green(`wt plugin add ${item.name}`)}`);
318
+ console.log(` ${pc.dim("Install:")} ${pc.green(`weavetab plugin add ${item.name}`)}`);
312
319
  console.log();
313
320
  }
314
321
  }
@@ -369,7 +376,7 @@ export async function runPluginBrowse() {
369
376
  export async function runPluginRemove(pkgName, args = []) {
370
377
  if (!pkgName || pkgName.startsWith("-")) {
371
378
  console.log(pc.red("[ERROR] Please specify the package name to remove."));
372
- console.log(pc.dim("Usage: wt plugin remove <packageName>"));
379
+ console.log(pc.dim("Usage: weavetab plugin remove <packageName>"));
373
380
  return;
374
381
  }
375
382
  const spinner = ora(`Uninstalling ${pc.cyan(pkgName)} via npm...`).start();
@@ -389,7 +396,7 @@ export async function runPluginRemove(pkgName, args = []) {
389
396
  export async function runPluginVerify(pkgName) {
390
397
  if (!pkgName || pkgName.startsWith("-")) {
391
398
  console.log(pc.red("[ERROR] Please specify a package name to verify."));
392
- console.log(pc.dim("Usage: wt plugin verify <packageName>"));
399
+ console.log(pc.dim("Usage: weavetab plugin verify <packageName>"));
393
400
  return;
394
401
  }
395
402
  const spinner = ora(`Checking trust status for ${pc.cyan(pkgName)}...`).start();
@@ -409,664 +416,7 @@ export async function runPluginVerify(pkgName) {
409
416
  }
410
417
  }
411
418
  // ---------------------------------------------------------------------------
412
- // 7. ENTERPRISE INIT: SCAFFOLD WEAVETAB PLUGIN
413
- // ---------------------------------------------------------------------------
414
- const DEFAULT_LOGO_SVG = `<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
415
- <rect width="128" height="128" rx="28" fill="#0D1117"/>
416
- <rect x="2" y="2" width="124" height="124" rx="26" stroke="#30363D" stroke-width="2"/>
417
- <path d="M64 24L104 64L64 104L24 64L64 24Z" fill="url(#blue_grad)" stroke="#58A6FF" stroke-width="3"/>
418
- <circle cx="64" cy="64" r="14" fill="#FFFFFF"/>
419
- <defs>
420
- <linearGradient id="blue_grad" x1="24" y1="24" x2="104" y2="104" gradientUnits="userSpaceOnUse">
421
- <stop stop-color="#2F81F7"/>
422
- <stop offset="1" stop-color="#1F6FEB"/>
423
- </linearGradient>
424
- </defs>
425
- </svg>`;
426
- const DEFAULT_BANNER_SVG = `<svg width="1200" height="400" viewBox="0 0 1200 400" fill="none" xmlns="http://www.w3.org/2000/svg">
427
- <rect width="1200" height="400" fill="#0D1117"/>
428
- <circle cx="600" cy="200" r="260" fill="#2F81F7" fill-opacity="0.12" filter="blur(80px)"/>
429
- <path d="M600 80L720 200L600 320L480 200L600 80Z" fill="url(#grad)" stroke="#58A6FF" stroke-width="4"/>
430
- <text x="600" y="360" text-anchor="middle" fill="#E6EDF3" font-family="-apple-system, BlinkMacSystemFont, Segoe UI, sans-serif" font-size="28" font-weight="600" letter-spacing="2">WEAVETAB MCP PLUGIN</text>
431
- <defs>
432
- <linearGradient id="grad" x1="480" y1="80" x2="720" y2="320" gradientUnits="userSpaceOnUse">
433
- <stop stop-color="#388BFD"/>
434
- <stop offset="1" stop-color="#1F6FEB"/>
435
- </linearGradient>
436
- </defs>
437
- </svg>`;
438
- export async function runPluginInit(args = []) {
439
- const isYes = args.includes("--yes") || args.includes("-y");
440
- const targetDirName = args.find((a) => !a.startsWith("-")) || "";
441
- let targetDir = process.cwd();
442
- if (targetDirName) {
443
- targetDir = path.resolve(process.cwd(), targetDirName);
444
- if (!existsSync(targetDir)) {
445
- await fs.mkdir(targetDir, { recursive: true });
446
- }
447
- }
448
- if (process.stdin.isTTY && !isYes) {
449
- console.clear();
450
- p.intro(`${pc.bgBlue(pc.white(" WEAVETAB "))} ${pc.bold(pc.cyan("Enterprise Plugin Generator"))}`);
451
- }
452
- let defaultName = path.basename(targetDir);
453
- let defaultPkgName = defaultName.startsWith("wt-") ? defaultName : `wt-${defaultName}`;
454
- let pkgName = defaultPkgName;
455
- let displayName = defaultName.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
456
- let description = "Weavetab Model Context Protocol (MCP) browser automation plugin.";
457
- let authorName = "Developer";
458
- let authorRole = "Maintainer";
459
- let templateType = "cdp";
460
- if (process.stdin.isTTY && !isYes) {
461
- const enteredPkgName = await p.text({
462
- message: "NPM Package Identifier (e.g. @org/wt-plugin or wt-plugin):",
463
- defaultValue: defaultPkgName,
464
- placeholder: defaultPkgName,
465
- });
466
- if (p.isCancel(enteredPkgName))
467
- process.exit(0);
468
- pkgName = enteredPkgName;
469
- const enteredDisplayName = await p.text({
470
- message: "Human-readable Display Name:",
471
- defaultValue: displayName,
472
- placeholder: displayName,
473
- });
474
- if (p.isCancel(enteredDisplayName))
475
- process.exit(0);
476
- displayName = enteredDisplayName;
477
- const enteredDesc = await p.text({
478
- message: "Description:",
479
- defaultValue: description,
480
- placeholder: description,
481
- });
482
- if (p.isCancel(enteredDesc))
483
- process.exit(0);
484
- description = enteredDesc;
485
- const enteredAuthor = await p.text({
486
- message: "Author Name or GitHub handle:",
487
- defaultValue: authorName,
488
- placeholder: authorName,
489
- });
490
- if (p.isCancel(enteredAuthor))
491
- process.exit(0);
492
- authorName = enteredAuthor;
493
- const enteredRole = await p.text({
494
- message: "Author Role (custom, e.g. Maintainer, Core Contributor, Creator):",
495
- defaultValue: "Maintainer",
496
- placeholder: "Maintainer",
497
- validate: (val) => {
498
- if (val && val.trim().length < 3)
499
- return "Role must be at least 3 characters long.";
500
- },
501
- });
502
- if (p.isCancel(enteredRole))
503
- process.exit(0);
504
- authorRole = enteredRole?.trim() || "Maintainer";
505
- const selectedTemplate = await p.select({
506
- message: "Select Plugin Architecture Template:",
507
- options: [
508
- {
509
- value: "cdp",
510
- label: `${pc.bold(pc.cyan("CDP Browser Automation"))} (Evaluates DOM, clicks elements, inspects tabs)`,
511
- },
512
- {
513
- value: "api",
514
- label: `${pc.bold(pc.green("External API Connector"))} (Exposes specialized MCP tools with JSON Schemas)`,
515
- },
516
- {
517
- value: "minimal",
518
- label: `${pc.bold(pc.gray("Minimal Starter"))} (Barebones TypeScript scaffold)`,
519
- },
520
- ],
521
- });
522
- if (p.isCancel(selectedTemplate))
523
- process.exit(0);
524
- templateType = selectedTemplate;
525
- }
526
- const spinner = ora(`Scaffolding enterprise plugin in ${pc.cyan(targetDir)}...`).start();
527
- // 1. Create directories
528
- const srcDir = path.join(targetDir, "src");
529
- const imgDir = path.join(targetDir, "images");
530
- const testDir = path.join(targetDir, "test");
531
- await fs.mkdir(srcDir, { recursive: true });
532
- await fs.mkdir(imgDir, { recursive: true });
533
- await fs.mkdir(testDir, { recursive: true });
534
- // 2. Assets (Logo & Banner)
535
- await fs.writeFile(path.join(imgDir, "logo.svg"), DEFAULT_LOGO_SVG, "utf-8");
536
- await fs.writeFile(path.join(imgDir, "banner.svg"), DEFAULT_BANNER_SVG, "utf-8");
537
- // 3. package.json
538
- const packageJsonContent = {
539
- name: pkgName,
540
- version: "1.0.0",
541
- description,
542
- main: "./dist/index.js",
543
- types: "./dist/index.d.ts",
544
- type: "module",
545
- files: ["dist", "images", "weavetab.json", "README.md"],
546
- scripts: {
547
- build: "tsc",
548
- watch: "tsc -w",
549
- prepare: "weavetab build",
550
- test: "node --test test/plugin.test.js",
551
- },
552
- keywords: [
553
- "weavetab",
554
- "weavetab-plugin",
555
- "mcp",
556
- "model-context-protocol",
557
- "browser-automation",
558
- ],
559
- author: authorName,
560
- license: "MIT",
561
- devDependencies: {
562
- typescript: "^5.7.2",
563
- },
564
- };
565
- await fs.writeFile(path.join(targetDir, "package.json"), JSON.stringify(packageJsonContent, null, 2), "utf-8");
566
- // 4. tsconfig.json
567
- const tsConfigContent = {
568
- compilerOptions: {
569
- target: "ES2022",
570
- module: "NodeNext",
571
- moduleResolution: "NodeNext",
572
- declaration: true,
573
- declarationMap: true,
574
- sourceMap: true,
575
- outDir: "./dist",
576
- rootDir: "./src",
577
- strict: true,
578
- esModuleInterop: true,
579
- skipLibCheck: true,
580
- },
581
- include: ["src/**/*"],
582
- };
583
- await fs.writeFile(path.join(targetDir, "tsconfig.json"), JSON.stringify(tsConfigContent, null, 2), "utf-8");
584
- // 5. .gitignore
585
- const gitignoreContent = `node_modules/
586
- dist/
587
- *.log
588
- .DS_Store
589
- `;
590
- await fs.writeFile(path.join(targetDir, ".gitignore"), gitignoreContent, "utf-8");
591
- // 6. src/index.ts
592
- const sanitizedFnName = pkgName.replace(/[^a-zA-Z0-9_]/g, "_").toLowerCase();
593
- const sourceCode = `/**
594
- * ${displayName}
595
- * Model Context Protocol (MCP) Plugin for Weavetab
596
- * Author: ${authorName}
597
- * License: MIT
598
- */
599
-
600
- export interface WeavetabSession {
601
- evaluate<T = any>(script: string): Promise<T>;
602
- click?(selector: string): Promise<any>;
603
- }
604
-
605
- export interface PluginToolArgs {
606
- query?: string;
607
- }
608
-
609
- export interface WeavetabPluginTool {
610
- name: string;
611
- description: string;
612
- schema?: Record<string, any>;
613
- handler: (args: PluginToolArgs, session?: WeavetabSession, config?: any) => Promise<any>;
614
- }
615
-
616
- export interface WeavetabPluginDefinition {
617
- name: string;
618
- version: string;
619
- description: string;
620
- tools: WeavetabPluginTool[];
621
- }
622
-
623
- export const plugin: WeavetabPluginDefinition = {
624
- name: "${pkgName}",
625
- version: "1.0.0",
626
- description: "${description}",
627
- tools: [
628
- {
629
- name: "${sanitizedFnName}",
630
- description: "Inspects live DOM telemetry and executes actions on the active browser tab.",
631
- schema: {
632
- type: "object",
633
- properties: {
634
- query: {
635
- type: "string",
636
- description: "Optional query or CSS selector for DOM inspection."
637
- }
638
- }
639
- },
640
- handler: async (args: PluginToolArgs, session?: WeavetabSession) => {
641
- if (!session || typeof session.evaluate !== "function") {
642
- return {
643
- status: "error",
644
- error: "No active Chrome DevTools Protocol (CDP) session attached."
645
- };
646
- }
647
-
648
- try {
649
- const pageData = await session.evaluate(\`
650
- (() => {
651
- return {
652
- title: document.title,
653
- url: window.location.href,
654
- elementsCount: document.querySelectorAll("*").length,
655
- ready: document.readyState
656
- };
657
- })()
658
- \`);
659
-
660
- return {
661
- status: "success",
662
- data: pageData,
663
- query: args?.query || null
664
- };
665
- } catch (err: any) {
666
- return {
667
- status: "error",
668
- error: err.message || String(err)
669
- };
670
- }
671
- }
672
- }
673
- ]
674
- };
675
-
676
- export default plugin;
677
- `;
678
- await fs.writeFile(path.join(srcDir, "index.ts"), sourceCode, "utf-8");
679
- // 7. weavetab.json
680
- const authorHandle = authorName.replace(/^@/, "").trim();
681
- const isGenericAuthor = ["author", "maintainer", "developer", "user"].includes(authorHandle.toLowerCase());
682
- const authorGhUrl = authorName.startsWith("http")
683
- ? authorName
684
- : (!isGenericAuthor && authorHandle && !authorHandle.includes(" "))
685
- ? `https://github.com/${authorHandle}`
686
- : undefined;
687
- const nodeMajor = process.versions.node ? process.versions.node.split(".")[0] : "18";
688
- const weavetabManifest = {
689
- $schema: "https://weavetab.dev/schema/plugin.json",
690
- name: displayName,
691
- version: "1.0.0",
692
- description,
693
- authors: [
694
- {
695
- name: authorHandle || "Author",
696
- role: authorRole,
697
- ...(authorGhUrl ? { url: authorGhUrl } : {}),
698
- },
699
- ],
700
- logo: "images/logo.svg",
701
- banner: "images/banner.svg",
702
- license: "MIT",
703
- tags: ["Automation", "Developer Tools", "MCP", "CDP"],
704
- compatibility: {
705
- weavetab: "^2.5.0",
706
- node: `>=${nodeMajor}.0.0`,
707
- },
708
- permissions: {
709
- network: {
710
- domains: ["*"],
711
- reason: "Required to inspect web tabs and telemetry.",
712
- },
713
- cdp: {
714
- evaluate: true,
715
- click: true,
716
- reason: "Evaluates DOM scripts and queries tab metadata via Chrome DevTools Protocol.",
717
- },
718
- },
719
- tools: [
720
- {
721
- name: sanitizedFnName,
722
- description: `Inspects live DOM telemetry and executes actions on the active browser tab.`,
723
- inputSchema: {
724
- type: "object",
725
- properties: {
726
- query: {
727
- type: "string",
728
- description: "Optional query or CSS selector for DOM inspection.",
729
- },
730
- },
731
- },
732
- },
733
- ],
734
- };
735
- await fs.writeFile(path.join(targetDir, "weavetab.json"), JSON.stringify(weavetabManifest, null, 2), "utf-8");
736
- // 8. README.md
737
- const readmeContent = `# ${displayName}
738
-
739
- > ${description}
740
-
741
- An enterprise Model Context Protocol (MCP) browser extension for **Weavetab**.
742
-
743
- ## Installation
744
-
745
- \`\`\`bash
746
- npx weavetab add ${pkgName}
747
- \`\`\`
748
-
749
- ## MCP Tools Exposed
750
-
751
- | Tool Name | Description | Parameters |
752
- | :--- | :--- | :--- |
753
- | \`${sanitizedFnName}\` | Inspects live DOM telemetry and executes actions on active tab | \`query\` (*optional*) |
754
-
755
- ## Security & Permissions
756
-
757
- - **Chrome DevTools Protocol (CDP)**: Evaluates DOM scripts on active tabs.
758
- - **Network Scope**: Scoped to active browser session.
759
-
760
- ## Development & Build
761
-
762
- \`\`\`bash
763
- # 1. Install dependencies
764
- npm install
765
-
766
- # 2. Build and compile plugin manifest
767
- npx weavetab build
768
-
769
- # 3. Publish to NPM
770
- npm publish --access public
771
- \`\`\`
772
- `;
773
- await fs.writeFile(path.join(targetDir, "README.md"), readmeContent, "utf-8");
774
- // 9. test/plugin.test.js
775
- const testContent = `import test from "node:test";
776
- import assert from "node:assert/strict";
777
-
778
- test("plugin exports valid Weavetab MCP tools", async () => {
779
- const { plugin } = await import("../dist/index.js");
780
- assert.ok(plugin, "Plugin module exported");
781
- assert.equal(typeof plugin.name, "string");
782
- assert.ok(Array.isArray(plugin.tools), "Plugin exports tools array");
783
- assert.ok(plugin.tools.length > 0, "Plugin defines at least 1 tool");
784
- });
785
- `;
786
- await fs.writeFile(path.join(testDir, "plugin.test.js"), testContent, "utf-8");
787
- spinner.succeed(pc.green(`Scaffolded ${pc.bold(displayName)} successfully!`));
788
- console.log();
789
- console.log(boxen(`${pc.bold(pc.cyan("✨ PLUGIN READY FOR DEVELOPMENT"))}\n\n` +
790
- ` ${pc.dim("Location:")} ${pc.bold(targetDir)}\n` +
791
- ` ${pc.dim("Package:")} ${pc.green(pkgName)}\n` +
792
- ` ${pc.dim("Tools:")} ${pc.yellow(sanitizedFnName)}\n\n` +
793
- `${pc.bold("Next Steps:")}\n` +
794
- ` 1. ${pc.cyan("npm install")}\n` +
795
- ` 2. ${pc.cyan("npx weavetab build")} ${pc.dim("(Compiles TS & syncs weavetab.json)")}\n` +
796
- ` 3. ${pc.cyan("npm publish --access public")}`, { padding: 1, borderStyle: "round", borderColor: "cyan" }));
797
- console.log();
798
- }
799
- // ---------------------------------------------------------------------------
800
- // 8. ENTERPRISE BUILD: COMPILE & SYNC WEAVETAB.JSON
801
- // ---------------------------------------------------------------------------
802
- export async function runPluginBuild(args = []) {
803
- const cwd = process.cwd();
804
- const pkgPath = path.join(cwd, "package.json");
805
- const manifestPath = path.join(cwd, "weavetab.json");
806
- const tsConfigPath = path.join(cwd, "tsconfig.json");
807
- console.log();
808
- console.log(boxen(pc.bold(pc.cyan(" WEAVETAB PLUGIN COMPILER ")), { padding: 0, borderStyle: "round", borderColor: "cyan" }));
809
- console.log();
810
- if (!existsSync(pkgPath)) {
811
- console.log(pc.red("[ERROR] No package.json found in current directory."));
812
- console.log(pc.dim("Run 'wt init' to scaffold a new Weavetab plugin project."));
813
- return;
814
- }
815
- const pkgJson = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
816
- const isTypeScript = existsSync(tsConfigPath);
817
- // 1. Compile TypeScript if applicable
818
- const entryRel = pkgJson.main || (isTypeScript ? "dist/index.js" : "index.js");
819
- const entryAbs = path.join(cwd, entryRel);
820
- if (isTypeScript) {
821
- const compileSpinner = ora("Compiling TypeScript plugin sources...").start();
822
- const localTsc = path.join(cwd, "node_modules", ".bin", process.platform === "win32" ? "tsc.cmd" : "tsc");
823
- let compiled = false;
824
- let lastError = "";
825
- if (existsSync(localTsc)) {
826
- const res = await runCommand(localTsc, [], cwd);
827
- if (res.code === 0)
828
- compiled = true;
829
- else
830
- lastError = res.stderr || res.stdout;
831
- }
832
- if (!compiled) {
833
- const npmRes = await runNpmCommand(["run", "build"], cwd);
834
- if (npmRes.code === 0)
835
- compiled = true;
836
- else
837
- lastError = npmRes.stderr || npmRes.stdout;
838
- }
839
- if (!compiled) {
840
- const npxRes = await runCommand("npx", ["-p", "typescript", "tsc"], cwd);
841
- if (npxRes.code === 0)
842
- compiled = true;
843
- else
844
- lastError = npxRes.stderr || npxRes.stdout;
845
- }
846
- if (compiled || existsSync(entryAbs)) {
847
- compileSpinner.succeed(pc.green("TypeScript compiled successfully."));
848
- }
849
- else {
850
- compileSpinner.fail(pc.red("TypeScript compilation failed."));
851
- if (lastError)
852
- console.error(pc.dim(lastError));
853
- return;
854
- }
855
- }
856
- // 2. Load compiled plugin module
857
- const inspectSpinner = ora("Introspecting exported MCP tools and schemas...").start();
858
- if (!existsSync(entryAbs)) {
859
- inspectSpinner.fail(pc.red(`Main entrypoint not found: ${entryRel}`));
860
- console.log(pc.dim("Ensure 'main' in package.json points to a valid compiled JavaScript file."));
861
- return;
862
- }
863
- let exportedTools = [];
864
- try {
865
- const fileUrl = pathToFileURL(entryAbs).href;
866
- const mod = await import(`${fileUrl}?t=${Date.now()}`);
867
- const pluginInstance = mod.default || mod.plugin || mod;
868
- if (pluginInstance && Array.isArray(pluginInstance.tools)) {
869
- exportedTools = pluginInstance.tools.map((t) => {
870
- const inputSchema = t.inputSchema || t.schema || {
871
- type: "object",
872
- properties: {},
873
- };
874
- return {
875
- name: t.name,
876
- description: t.description || "",
877
- inputSchema,
878
- };
879
- });
880
- }
881
- inspectSpinner.succeed(`Discovered ${pc.cyan(String(exportedTools.length))} MCP tool(s).`);
882
- }
883
- catch (err) {
884
- inspectSpinner.warn(pc.yellow(`Dynamic introspection note: ${err.message}`));
885
- }
886
- // 3. Read or create weavetab.json
887
- let manifest = {
888
- $schema: "https://weavetab.dev/schema/plugin.json",
889
- name: pkgJson.name || path.basename(cwd),
890
- version: pkgJson.version || "1.0.0",
891
- description: pkgJson.description || "",
892
- logo: "images/logo.svg",
893
- banner: "images/banner.svg",
894
- license: pkgJson.license || "MIT",
895
- tags: ["MCP", "Automation"],
896
- };
897
- if (existsSync(manifestPath)) {
898
- try {
899
- manifest = JSON.parse(await fs.readFile(manifestPath, "utf-8"));
900
- }
901
- catch {
902
- console.log(pc.yellow("Warning: Existing weavetab.json was malformed, rebuilding cleanly."));
903
- }
904
- }
905
- // 4. Synchronize metadata & tools
906
- manifest.$schema = "https://weavetab.dev/schema/plugin.json";
907
- manifest.version = pkgJson.version || manifest.version || "1.0.0";
908
- if (!manifest.description && pkgJson.description) {
909
- manifest.description = pkgJson.description;
910
- }
911
- // Sync authors
912
- if (!manifest.authors && !manifest.author) {
913
- manifest.authors = [
914
- {
915
- name: pkgJson.author || "Maintainer",
916
- role: "Maintainer",
917
- },
918
- ];
919
- }
920
- // Sync compatibility
921
- if (!manifest.compatibility) {
922
- const nodeMajor = process.versions.node ? process.versions.node.split(".")[0] : "18";
923
- manifest.compatibility = {
924
- weavetab: "^2.5.0",
925
- node: pkgJson.engines?.node || `>=${nodeMajor}.0.0`,
926
- };
927
- }
928
- // Sync tools array with introspected definitions
929
- if (exportedTools.length > 0) {
930
- manifest.tools = exportedTools;
931
- }
932
- // Ensure default permissions exist if empty
933
- if (!manifest.permissions) {
934
- manifest.permissions = {
935
- cdp: {
936
- evaluate: true,
937
- reason: "Evaluates DOM telemetry and executes automated user actions.",
938
- },
939
- };
940
- }
941
- // 5. Comprehensive Manifest Validation & Audit Rules
942
- const errors = [];
943
- const warnings = [];
944
- // Name validation
945
- if (!manifest.name || typeof manifest.name !== "string" || manifest.name.trim().length === 0) {
946
- errors.push("Plugin 'name' is required and cannot be empty.");
947
- }
948
- else if (["my-plugin", "plugin-starter", "plugin-template", "example"].includes(manifest.name.toLowerCase())) {
949
- warnings.push(`Plugin name '${manifest.name}' appears to be a placeholder. Consider setting a descriptive name.`);
950
- }
951
- // Version semver validation
952
- const semverRegex = /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/;
953
- if (!manifest.version || !semverRegex.test(manifest.version)) {
954
- errors.push(`Plugin version '${manifest.version}' is invalid. Must follow Semantic Versioning (e.g. 1.0.0).`);
955
- }
956
- // Description validation
957
- if (!manifest.description || manifest.description.trim().length < 10) {
958
- warnings.push("Plugin 'description' is missing or very short. Provide a clear summary for users on the registry.");
959
- }
960
- // Authors validation
961
- const authorsList = Array.isArray(manifest.authors)
962
- ? manifest.authors
963
- : manifest.author
964
- ? (Array.isArray(manifest.author) ? manifest.author : [manifest.author])
965
- : [];
966
- if (authorsList.length === 0) {
967
- errors.push("At least one author must be declared in 'authors' or package.json.");
968
- }
969
- else {
970
- for (const a of authorsList) {
971
- if (typeof a === "object" && a !== null) {
972
- if (!a.name || String(a.name).trim().length < 2) {
973
- errors.push(`Author name '${a.name || ""}' must be at least 2 characters.`);
974
- }
975
- if (a.role !== undefined && a.role !== null) {
976
- const roleStr = String(a.role).trim();
977
- if (roleStr.length < 3) {
978
- errors.push(`Invalid author role for '${a.name || "author"}': "${roleStr}". Role must be at least 3 characters (e.g. 'Creator', 'Maintainer', 'Lead Architect').`);
979
- }
980
- }
981
- if (a.url) {
982
- try {
983
- const parsedUrl = new URL(a.url);
984
- if (!["http:", "https:"].includes(parsedUrl.protocol)) {
985
- errors.push(`Author URL '${a.url}' must use HTTP or HTTPS protocol.`);
986
- }
987
- }
988
- catch {
989
- errors.push(`Author URL '${a.url}' is not a valid URL.`);
990
- }
991
- }
992
- }
993
- }
994
- }
995
- // Tools validation
996
- if (!manifest.tools || manifest.tools.length === 0) {
997
- warnings.push("No MCP tools declared or discovered. The plugin will not expose any capabilities to AI agents.");
998
- }
999
- else {
1000
- for (const tool of manifest.tools) {
1001
- if (!tool.name || !/^[a-zA-Z0-9_-]+$/.test(tool.name)) {
1002
- errors.push(`Tool name '${tool.name}' is invalid. Must only contain letters, numbers, underscores, or hyphens.`);
1003
- }
1004
- if (!tool.description || tool.description.trim().length < 5) {
1005
- warnings.push(`Tool '${tool.name}' has a very short description. Write a clear description so AI agents understand its purpose.`);
1006
- }
1007
- }
1008
- }
1009
- // Permissions validation
1010
- if (manifest.permissions?.network?.domains?.includes("*")) {
1011
- warnings.push("Wildcard domain access ('*') requested in network permissions. Narrowing to specific domains improves security.");
1012
- }
1013
- if (manifest.permissions?.cdp && (!manifest.permissions.cdp.reason || manifest.permissions.cdp.reason.trim().length < 5)) {
1014
- warnings.push("Missing justification in permissions.cdp.reason. Explain why Chrome DevTools Protocol access is required.");
1015
- }
1016
- // Asset files validation
1017
- if (manifest.logo && typeof manifest.logo === "string") {
1018
- const logoPath = path.resolve(cwd, manifest.logo);
1019
- if (!existsSync(logoPath)) {
1020
- warnings.push(`Referenced logo asset '${manifest.logo}' was not found at '${path.relative(cwd, logoPath)}'.`);
1021
- }
1022
- }
1023
- if (manifest.banner && typeof manifest.banner === "string") {
1024
- const bannerPath = path.resolve(cwd, manifest.banner);
1025
- if (!existsSync(bannerPath)) {
1026
- warnings.push(`Referenced banner asset '${manifest.banner}' was not found at '${path.relative(cwd, bannerPath)}'.`);
1027
- }
1028
- }
1029
- // Print Warnings
1030
- if (warnings.length > 0) {
1031
- console.log();
1032
- console.log(pc.yellow(pc.bold("⚠ WEAVETAB BUILD WARNINGS:")));
1033
- for (const w of warnings) {
1034
- console.log(` ${pc.yellow("•")} ${w}`);
1035
- }
1036
- }
1037
- // Print Errors and abort if any
1038
- if (errors.length > 0) {
1039
- console.log();
1040
- console.log(pc.red(pc.bold("✖ WEAVETAB BUILD FAILED WITH ERRORS:")));
1041
- for (const e of errors) {
1042
- console.log(` ${pc.red("•")} ${e}`);
1043
- }
1044
- console.log();
1045
- process.exit(1);
1046
- }
1047
- // 6. Write back synced weavetab.json
1048
- await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
1049
- // 6. Print Summary Report
1050
- const declaredToolsList = manifest.tools?.map((t) => ` • ${pc.bold(pc.cyan(t.name))} - ${pc.dim(t.description)}`).join("\n") || pc.dim(" (None declared)");
1051
- const perms = [];
1052
- if (manifest.permissions?.cdp)
1053
- perms.push("CDP (Browser Automation)");
1054
- if (manifest.permissions?.network)
1055
- perms.push(`Network (${manifest.permissions.network.domains?.join(", ") || "Active Tab"})`);
1056
- if (manifest.permissions?.fs)
1057
- perms.push("Local Filesystem");
1058
- console.log(boxen(`${pc.bold(pc.green("✔ WEAVETAB PLUGIN BUILD COMPLETED"))}\n\n` +
1059
- ` ${pc.dim("Package:")} ${pc.bold(pkgJson.name || manifest.name)} (v${manifest.version})\n` +
1060
- ` ${pc.dim("Entrypoint:")} ${pc.cyan(entryRel)}\n` +
1061
- ` ${pc.dim("Permissions:")} ${pc.yellow(perms.join(", ") || "Standard")}\n` +
1062
- ` ${pc.dim("Manifest:")} ${pc.green("weavetab.json (Synced & Validated)")}\n\n` +
1063
- `${pc.bold("Exposed MCP Tools:")}\n${declaredToolsList}\n\n` +
1064
- `${pc.dim("Ready to publish to NPM:")}\n` +
1065
- ` ${pc.bold(pc.cyan("npm publish --access public"))}`, { padding: 1, borderStyle: "round", borderColor: "green" }));
1066
- console.log();
1067
- }
1068
- // ---------------------------------------------------------------------------
1069
- // 9. MAIN CLI ROUTER FOR PLUGINS
419
+ // 7. MAIN CLI ROUTER FOR PLUGINS (User / Operations Mode)
1070
420
  // ---------------------------------------------------------------------------
1071
421
  export async function runPluginCli(args) {
1072
422
  const subcmd = args[0]?.toLowerCase();
@@ -1075,14 +425,9 @@ export async function runPluginCli(args) {
1075
425
  console.log(boxen(pc.bold(pc.cyan(" WEAVETAB PLUGIN MANAGER ")), { padding: 0, borderStyle: "round", borderColor: "cyan" }));
1076
426
  console.log();
1077
427
  console.log(pc.bold("USAGE"));
1078
- console.log(` wt plugin <command> [options]`);
1079
- console.log();
1080
- console.log(pc.bold("DEVELOPER COMMANDS"));
1081
- console.log(` ${pc.cyan("init [name]")} Scaffold a new enterprise TypeScript Weavetab plugin`);
1082
- console.log(` ${pc.cyan("build")} Compile TypeScript & synchronize weavetab.json manifest`);
1083
- console.log(` ${pc.cyan("manifest")} Alias for 'build' to validate & sync manifest`);
428
+ console.log(` weavetab plugin <command> [options]`);
1084
429
  console.log();
1085
- console.log(pc.bold("USER COMMANDS"));
430
+ console.log(pc.bold("COMMANDS"));
1086
431
  console.log(` ${pc.cyan("add <pkg>")} Install a plugin (resolves official @weavetab/ & community)`);
1087
432
  console.log(` ${pc.cyan("browse")} Interactive terminal explorer to browse & 1-click install`);
1088
433
  console.log(` ${pc.cyan("search [query]")} Search plugins across official registry & npm`);
@@ -1090,6 +435,10 @@ export async function runPluginCli(args) {
1090
435
  console.log(` ${pc.cyan("remove <pkg>")} Uninstall a plugin from local environment`);
1091
436
  console.log(` ${pc.cyan("verify <pkg>")} Check trust tier and registry verification status`);
1092
437
  console.log();
438
+ console.log(pc.bold("DEVELOPER SDK (@weavetab/sdk)"));
439
+ console.log(` ${pc.dim("Scaffold a plugin:")} ${pc.cyan("npx -y @weavetab/sdk init <name>")}`);
440
+ console.log(` ${pc.dim("Build & validate:")} ${pc.cyan("npx @weavetab/sdk build")}`);
441
+ console.log();
1093
442
  console.log(pc.bold("OPTIONS (for 'add')"));
1094
443
  console.log(` ${pc.cyan("--official, -O")} Prefer official @weavetab/plugin-<name>`);
1095
444
  console.log(` ${pc.cyan("--community, -C")} Prefer community package`);
@@ -1097,12 +446,11 @@ export async function runPluginCli(args) {
1097
446
  console.log();
1098
447
  return;
1099
448
  }
1100
- if (subcmd === "init" || subcmd === "create" || subcmd === "new") {
1101
- await runPluginInit(args.slice(1));
1102
- return;
1103
- }
1104
- if (subcmd === "build" || subcmd === "manifest" || subcmd === "sync") {
1105
- await runPluginBuild(args.slice(1));
449
+ if (subcmd === "init" || subcmd === "create" || subcmd === "new" || subcmd === "build" || subcmd === "manifest") {
450
+ console.log(pc.yellow(`\n[Weavetab] Plugin authoring commands belong to the developer SDK (@weavetab/sdk).`));
451
+ console.log(pc.dim("To scaffold a new plugin: ") + pc.cyan("npx -y @weavetab/sdk init <name>"));
452
+ console.log(pc.dim("To build/validate a plugin: ") + pc.cyan("npx @weavetab/sdk build"));
453
+ console.log(pc.dim("SDK documentation: ") + pc.cyan("https://github.com/weavetab/sdk\n"));
1106
454
  return;
1107
455
  }
1108
456
  if (subcmd === "add" || subcmd === "install" || subcmd === "i") {
@@ -1130,5 +478,5 @@ export async function runPluginCli(args) {
1130
478
  return;
1131
479
  }
1132
480
  console.log(pc.red(`[ERROR] Unknown plugin subcommand: "${subcmd}"`));
1133
- console.log(pc.dim("Run 'wt plugin --help' to see available commands."));
481
+ console.log(pc.dim("Run 'weavetab plugin --help' to see available commands."));
1134
482
  }