@weavetab/mcp 2.5.0-beta.1 → 2.5.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -1
- package/ARCHITECTURE.md +6 -6
- package/LICENSE +1 -1
- package/README.md +164 -802
- package/SECURITY.md +33 -22
- package/TROUBLESHOOTING.md +3 -3
- package/dist/cdp/bridge.d.ts +10 -0
- package/dist/cdp/bridge.js +285 -78
- package/dist/cdp/connector.d.ts +7 -3
- package/dist/cdp/connector.js +196 -75
- package/dist/cdp/helpers.d.ts +4 -0
- package/dist/cdp/helpers.js +181 -0
- package/dist/cdp/lock.d.ts +9 -6
- package/dist/cdp/lock.js +72 -59
- package/dist/cdp/omni_broker.d.ts +2 -1
- package/dist/cdp/omni_broker.js +13 -7
- package/dist/cdp/profiles.d.ts +10 -0
- package/dist/cdp/profiles.js +65 -0
- package/dist/cdp/walker.d.ts +25 -1
- package/dist/cdp/walker.js +354 -7
- package/dist/cli/plugin.d.ts +0 -2
- package/dist/cli/plugin.js +51 -696
- package/dist/cli/updater.d.ts +1 -1
- package/dist/cli/updater.js +27 -7
- package/dist/config/loader.d.ts +33 -6
- package/dist/config/loader.js +174 -22
- package/dist/desktop/discovery.d.ts +44 -0
- package/dist/desktop/discovery.js +364 -0
- package/dist/index.js +140 -64
- package/dist/intelligence/marks.d.ts +36 -0
- package/dist/intelligence/marks.js +30 -0
- package/dist/intelligence/patternCompiler.d.ts +118 -0
- package/dist/intelligence/patternCompiler.js +259 -0
- package/dist/intelligence/sessionMemory.d.ts +2 -0
- package/dist/intelligence/sessionMemory.js +18 -8
- package/dist/overlay/ghost.js +2 -2
- package/dist/overlay/injector.js +3 -5
- package/dist/plugin/extension_bridge.d.ts +40 -0
- package/dist/plugin/extension_bridge.js +158 -0
- package/dist/plugin/interface.d.ts +151 -15
- package/dist/plugin/loader.d.ts +19 -1
- package/dist/plugin/loader.js +331 -63
- package/dist/plugin/pipeline.d.ts +75 -0
- package/dist/plugin/pipeline.js +183 -0
- package/dist/plugin/registry.js +12 -1
- package/dist/plugin/storage.d.ts +51 -0
- package/dist/plugin/storage.js +164 -0
- package/dist/security/secrets.d.ts +1 -0
- package/dist/security/secrets.js +13 -0
- package/dist/sensors/actionability.js +1 -2
- package/dist/sensors/guard.js +4 -10
- package/dist/sensors/mutations.js +12 -0
- package/dist/sensors/operation_monitor.js +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +600 -236
- package/dist/state/agent.d.ts +1 -0
- package/dist/state/agent.js +3 -0
- package/dist/state/delta.d.ts +12 -4
- package/dist/state/delta.js +67 -14
- package/dist/state/session.d.ts +8 -2
- package/dist/state/session.js +60 -13
- package/dist/tools/browser_detect.d.ts +16 -2
- package/dist/tools/browser_detect.js +54 -6
- package/dist/tools/burst.d.ts +17 -7
- package/dist/tools/burst.js +240 -83
- package/dist/tools/checkpoint.d.ts +38 -0
- package/dist/tools/checkpoint.js +271 -0
- package/dist/tools/click.d.ts +1 -0
- package/dist/tools/click.js +97 -98
- package/dist/tools/clipboard.js +31 -24
- package/dist/tools/design_extract.js +1 -1
- package/dist/tools/eval.js +1 -1
- package/dist/tools/fill.d.ts +20 -1
- package/dist/tools/fill.js +199 -40
- package/dist/tools/find.d.ts +16 -0
- package/dist/tools/find.js +67 -44
- package/dist/tools/github/index.d.ts +19 -4
- package/dist/tools/github/index.js +40 -4
- package/dist/tools/highlight.d.ts +6 -2
- package/dist/tools/highlight.js +158 -72
- package/dist/tools/inspect.js +1 -1
- package/dist/tools/key.js +65 -56
- package/dist/tools/navigate.d.ts +1 -1
- package/dist/tools/navigate.js +57 -44
- package/dist/tools/pdf.js +21 -13
- package/dist/tools/pointer.d.ts +18 -3
- package/dist/tools/pointer.js +89 -1
- package/dist/tools/read.d.ts +28 -8
- package/dist/tools/read.js +230 -56
- package/dist/tools/scrape.js +67 -13
- package/dist/tools/screenshot.js +21 -16
- package/dist/tools/scroll.js +6 -11
- package/dist/tools/select.js +8 -2
- package/dist/tools/snapshot.js +3 -34
- package/dist/tools/tabs.d.ts +10 -10
- package/dist/tools/tabs.js +55 -39
- package/dist/tools/thought.d.ts +2 -0
- package/dist/tools/thought.js +13 -14
- package/dist/tools/type.d.ts +2 -0
- package/dist/tools/type.js +109 -60
- package/dist/tools/type_secret.js +42 -76
- package/dist/tools/upload.js +1 -1
- package/dist/tools/video_compiler.d.ts +1 -1
- package/dist/tools/video_compiler.js +11 -12
- package/dist/version.d.ts +5 -0
- package/dist/version.js +5 -0
- package/docs/DOCUMENTATION.md +82 -36
- package/docs/PLUGINS.md +82 -499
- package/docs/TOOLS.md +51 -99
- package/docs/architecture/blind-injection.md +83 -0
- package/docs/architecture/dual-injection.md +32 -0
- package/docs/architecture/overview.md +49 -0
- package/docs/architecture/security.md +35 -0
- package/docs/architecture/transport.md +37 -0
- package/docs/captcha-stealth/captcha-solver.md +75 -0
- package/docs/captcha-stealth/stealth-physics.md +60 -0
- package/docs/cli/cli-commands.md +44 -0
- package/docs/cli/cli-flags.md +20 -0
- package/docs/cli/cli-introduction.md +20 -0
- package/docs/cli/cli-scripting.md +32 -0
- package/docs/cli/g-ide/ide-antigravity.md +24 -0
- package/docs/cli/g-ide/ide-claude-code.md +24 -0
- package/docs/cli/g-ide/ide-claude-desktop.md +32 -0
- package/docs/cli/g-ide/ide-cursor.md +31 -0
- package/docs/cli/g-ide/ide-generic.md +34 -0
- package/docs/cli/g-ide/ide-opencode.md +24 -0
- package/docs/cli/g-ide/ide-vscode-copilot.md +24 -0
- package/docs/cli/g-ide/ide-windsurf.md +24 -0
- package/docs/configuration/config-locations.md +24 -0
- package/docs/configuration/configuration.md +73 -0
- package/docs/configuration/env-variables.md +19 -0
- package/docs/configuration/folders.md +55 -0
- package/docs/desktop-automation/electron-apps.md +217 -0
- package/docs/get-started/installation.md +47 -0
- package/docs/get-started/introduction.md +60 -0
- package/docs/get-started/quickstart.md +54 -0
- package/docs/get-started/setup-wizard.md +26 -0
- package/docs/intelligence/site-profiles.md +151 -0
- package/docs/skills-ecosystem/skills-overview.md +35 -0
- package/docs/skills-ecosystem/skills-recipes.md +36 -0
- package/docs/tools/tools.md +631 -0
- package/docs/troubleshooting/trouble-browser.md +27 -0
- package/docs/troubleshooting/trouble-config.md +20 -0
- package/docs/troubleshooting/trouble-loop.md +31 -0
- package/ext-dist/background.js +10 -62
- package/ext-dist/content.js +333 -921
- package/ext-dist/hud/hud.js +9 -9
- package/ext-dist/manifest.json +2 -6
- package/ext-dist/styles.css +6 -1
- package/mcp.json +108 -72
- package/package.json +14 -9
- package/server.json +3 -3
- package/docs/DEV_MODE.md +0 -68
- package/docs/dev_plugin.md +0 -310
- package/ext-dist/sidepanel/sidepanel.js +0 -25
- package/ext-dist/sidepanel.html +0 -547
package/dist/cli/plugin.js
CHANGED
|
@@ -2,13 +2,21 @@ 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";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
7
|
+
import { createRequire } from "node:module";
|
|
8
|
+
import { WEAVETAB_VERSION } from "../version.js";
|
|
9
|
+
const _require = createRequire(import.meta.url);
|
|
10
|
+
function getVersion() {
|
|
11
|
+
try {
|
|
12
|
+
return _require("../../package.json").version || WEAVETAB_VERSION;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return WEAVETAB_VERSION;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
import { getVerifiedPackages, resolvePluginTrust, resolvePluginCandidates, invalidateRegistryCache, REGISTRY_URL, } from "../plugin/registry.js";
|
|
19
|
+
import { listInstalledPlugins, inspectInstalledPackage, normalizePermissions } from "../plugin/loader.js";
|
|
12
20
|
// Helper to run child process safely
|
|
13
21
|
function runCommand(cmd, cmdArgs, cwd = process.cwd()) {
|
|
14
22
|
return new Promise((resolve) => {
|
|
@@ -16,7 +24,7 @@ function runCommand(cmd, cmdArgs, cwd = process.cwd()) {
|
|
|
16
24
|
const executable = isWin && !cmd.endsWith(".cmd") && !cmd.endsWith(".exe") ? `${cmd}.cmd` : cmd;
|
|
17
25
|
const child = spawn(executable, cmdArgs, {
|
|
18
26
|
cwd,
|
|
19
|
-
shell:
|
|
27
|
+
shell: false,
|
|
20
28
|
stdio: ["ignore", "pipe", "pipe"],
|
|
21
29
|
});
|
|
22
30
|
let stdout = "";
|
|
@@ -40,7 +48,7 @@ function runNpmCommand(cmdArgs, cwd = process.cwd()) {
|
|
|
40
48
|
export async function runPluginAdd(inputName, args = []) {
|
|
41
49
|
if (!inputName || inputName.startsWith("-")) {
|
|
42
50
|
console.log(pc.red("[ERROR] Please provide a package name to install."));
|
|
43
|
-
console.log(pc.dim("Usage:
|
|
51
|
+
console.log(pc.dim("Usage: weavetab plugin add <packageName> [--official | --community] [--yes]"));
|
|
44
52
|
return;
|
|
45
53
|
}
|
|
46
54
|
const isForce = args.includes("--yes") || args.includes("-y") || args.includes("--force");
|
|
@@ -160,14 +168,14 @@ export async function runPluginAdd(inputName, args = []) {
|
|
|
160
168
|
}
|
|
161
169
|
return;
|
|
162
170
|
}
|
|
163
|
-
spinner.succeed(pc.green(`
|
|
171
|
+
spinner.succeed(pc.green(`installed ${pc.bold(selectedPkg)}`));
|
|
164
172
|
// Inspect installed package for weavetab.json
|
|
165
173
|
const targetDir = path.join(process.cwd(), "node_modules", selectedPkg);
|
|
166
174
|
const installedInfo = inspectInstalledPackage(targetDir);
|
|
167
175
|
if (installedInfo && installedInfo.manifest) {
|
|
168
176
|
const manifest = installedInfo.manifest;
|
|
169
177
|
const tools = manifest.tools || [];
|
|
170
|
-
const permissions = manifest.permissions
|
|
178
|
+
const permissions = normalizePermissions(manifest.permissions);
|
|
171
179
|
const infoLines = [
|
|
172
180
|
`${pc.bold("Plugin Details:")}`,
|
|
173
181
|
` ${pc.dim("Name:")} ${manifest.name || selectedPkg}`,
|
|
@@ -210,7 +218,7 @@ export async function runPluginAdd(inputName, args = []) {
|
|
|
210
218
|
console.log();
|
|
211
219
|
console.log(boxen(`${pc.yellow("⚠️ NOTE: No 'weavetab.json' manifest was detected inside this package.")}\n` +
|
|
212
220
|
pc.dim("Weavetab requires a valid weavetab.json manifest to automatically register tools.\n") +
|
|
213
|
-
pc.dim(`If you are the author,
|
|
221
|
+
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
222
|
console.log();
|
|
215
223
|
}
|
|
216
224
|
}
|
|
@@ -225,7 +233,7 @@ export async function runPluginList() {
|
|
|
225
233
|
console.log();
|
|
226
234
|
if (plugins.length === 0) {
|
|
227
235
|
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("
|
|
236
|
+
console.log(pc.dim(`Install official or community plugins using: ${pc.cyan("weavetab plugin add <packageName>")}\n`));
|
|
229
237
|
return;
|
|
230
238
|
}
|
|
231
239
|
console.log(pc.dim(`Found ${plugins.length} installed plugin(s):\n`));
|
|
@@ -269,7 +277,7 @@ export async function runPluginSearch(query) {
|
|
|
269
277
|
const searchQuery = q ? `weavetab ${q}` : "weavetab plugin";
|
|
270
278
|
const res = await fetch(`https://registry.npmjs.org/-/v1/search?text=${encodeURIComponent(searchQuery)}&size=15`, {
|
|
271
279
|
signal: AbortSignal.timeout(3500),
|
|
272
|
-
headers: { "User-Agent":
|
|
280
|
+
headers: { "User-Agent": `Weavetab/${getVersion()}` },
|
|
273
281
|
});
|
|
274
282
|
if (res.ok) {
|
|
275
283
|
const data = (await res.json());
|
|
@@ -301,14 +309,14 @@ export async function runPluginSearch(query) {
|
|
|
301
309
|
console.log();
|
|
302
310
|
if (results.length === 0) {
|
|
303
311
|
console.log(pc.yellow(`No plugins matching "${q}" found.`));
|
|
304
|
-
console.log(pc.dim(`Try browsing the registry or visit ${pc.cyan("https://
|
|
312
|
+
console.log(pc.dim(`Try browsing the registry or visit ${pc.cyan("https://github.com/weavetab/mcp/plugins")}\n`));
|
|
305
313
|
return;
|
|
306
314
|
}
|
|
307
315
|
console.log(pc.dim(`Found ${results.length} matching plugin(s):\n`));
|
|
308
316
|
for (const item of results) {
|
|
309
317
|
console.log(`${item.badge} ${pc.bold(pc.cyan(item.name))} ${pc.dim(`by ${item.author}`)}`);
|
|
310
318
|
console.log(` ${pc.dim(item.description)}`);
|
|
311
|
-
console.log(` ${pc.dim("Install:")} ${pc.green(`
|
|
319
|
+
console.log(` ${pc.dim("Install:")} ${pc.green(`weavetab plugin add ${item.name}`)}`);
|
|
312
320
|
console.log();
|
|
313
321
|
}
|
|
314
322
|
}
|
|
@@ -369,7 +377,7 @@ export async function runPluginBrowse() {
|
|
|
369
377
|
export async function runPluginRemove(pkgName, args = []) {
|
|
370
378
|
if (!pkgName || pkgName.startsWith("-")) {
|
|
371
379
|
console.log(pc.red("[ERROR] Please specify the package name to remove."));
|
|
372
|
-
console.log(pc.dim("Usage:
|
|
380
|
+
console.log(pc.dim("Usage: weavetab plugin remove <packageName>"));
|
|
373
381
|
return;
|
|
374
382
|
}
|
|
375
383
|
const spinner = ora(`Uninstalling ${pc.cyan(pkgName)} via npm...`).start();
|
|
@@ -380,7 +388,7 @@ export async function runPluginRemove(pkgName, args = []) {
|
|
|
380
388
|
console.error(pc.dim(result.stderr));
|
|
381
389
|
return;
|
|
382
390
|
}
|
|
383
|
-
spinner.succeed(pc.green(`
|
|
391
|
+
spinner.succeed(pc.green(`removed ${pc.bold(pkgName)}`));
|
|
384
392
|
console.log(pc.dim("The plugin and its tools have been uninstalled.\n"));
|
|
385
393
|
}
|
|
386
394
|
// ---------------------------------------------------------------------------
|
|
@@ -389,7 +397,7 @@ export async function runPluginRemove(pkgName, args = []) {
|
|
|
389
397
|
export async function runPluginVerify(pkgName) {
|
|
390
398
|
if (!pkgName || pkgName.startsWith("-")) {
|
|
391
399
|
console.log(pc.red("[ERROR] Please specify a package name to verify."));
|
|
392
|
-
console.log(pc.dim("Usage:
|
|
400
|
+
console.log(pc.dim("Usage: weavetab plugin verify <packageName>"));
|
|
393
401
|
return;
|
|
394
402
|
}
|
|
395
403
|
const spinner = ora(`Checking trust status for ${pc.cyan(pkgName)}...`).start();
|
|
@@ -409,704 +417,51 @@ export async function runPluginVerify(pkgName) {
|
|
|
409
417
|
}
|
|
410
418
|
}
|
|
411
419
|
// ---------------------------------------------------------------------------
|
|
412
|
-
// 7.
|
|
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
|
|
420
|
+
// 7. MAIN CLI ROUTER FOR PLUGINS (User / Operations Mode)
|
|
1070
421
|
// ---------------------------------------------------------------------------
|
|
1071
422
|
export async function runPluginCli(args) {
|
|
1072
|
-
|
|
423
|
+
if (args.includes("--refresh")) {
|
|
424
|
+
invalidateRegistryCache();
|
|
425
|
+
console.log(pc.green("[OK] Plugin registry cache refreshed.\n"));
|
|
426
|
+
}
|
|
427
|
+
const cleanArgs = args.filter((a) => a !== "--refresh");
|
|
428
|
+
const subcmd = cleanArgs[0]?.toLowerCase();
|
|
1073
429
|
if (!subcmd || subcmd === "--help" || subcmd === "-h" || subcmd === "help") {
|
|
1074
430
|
console.log();
|
|
1075
431
|
console.log(boxen(pc.bold(pc.cyan(" WEAVETAB PLUGIN MANAGER ")), { padding: 0, borderStyle: "round", borderColor: "cyan" }));
|
|
1076
432
|
console.log();
|
|
1077
433
|
console.log(pc.bold("USAGE"));
|
|
1078
|
-
console.log(`
|
|
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`);
|
|
434
|
+
console.log(` weavetab plugin <command> [options]`);
|
|
1084
435
|
console.log();
|
|
1085
|
-
console.log(pc.bold("
|
|
1086
|
-
console.log(` ${pc.cyan("add <pkg>")} Install
|
|
436
|
+
console.log(pc.bold("COMMANDS"));
|
|
437
|
+
console.log(` ${pc.cyan("add <pkg>")} Install any plugin by npm package name (e.g. @fy2ne/wt-youtube, my-plugin)`);
|
|
1087
438
|
console.log(` ${pc.cyan("browse")} Interactive terminal explorer to browse & 1-click install`);
|
|
1088
439
|
console.log(` ${pc.cyan("search [query]")} Search plugins across official registry & npm`);
|
|
1089
440
|
console.log(` ${pc.cyan("list")} List all installed plugins and their registered tools`);
|
|
1090
441
|
console.log(` ${pc.cyan("remove <pkg>")} Uninstall a plugin from local environment`);
|
|
1091
442
|
console.log(` ${pc.cyan("verify <pkg>")} Check trust tier and registry verification status`);
|
|
1092
443
|
console.log();
|
|
1093
|
-
console.log(pc.bold("
|
|
444
|
+
console.log(pc.bold("DEVELOPER SDK (@weavetab/sdk)"));
|
|
445
|
+
console.log(` ${pc.dim("Scaffold a plugin:")} ${pc.cyan("npx @weavetab/sdk init <name>")}`);
|
|
446
|
+
console.log(` ${pc.dim("Build & validate:")} ${pc.cyan("npx @weavetab/sdk build")}`);
|
|
447
|
+
console.log();
|
|
448
|
+
console.log(pc.bold("OPTIONS (for 'add' / general)"));
|
|
449
|
+
console.log(` ${pc.cyan("--refresh")} Invalidate and refresh the verified plugin cache`);
|
|
1094
450
|
console.log(` ${pc.cyan("--official, -O")} Prefer official @weavetab/plugin-<name>`);
|
|
1095
451
|
console.log(` ${pc.cyan("--community, -C")} Prefer community package`);
|
|
1096
452
|
console.log(` ${pc.cyan("--yes, -y")} Bypass interactive warning prompt for unverified plugins`);
|
|
1097
453
|
console.log();
|
|
1098
454
|
return;
|
|
1099
455
|
}
|
|
1100
|
-
if (subcmd === "init" || subcmd === "create" || subcmd === "new") {
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
await runPluginBuild(args.slice(1));
|
|
456
|
+
if (subcmd === "init" || subcmd === "create" || subcmd === "new" || subcmd === "build" || subcmd === "manifest") {
|
|
457
|
+
console.log(pc.yellow(`\n[Weavetab] Plugin authoring commands belong to the developer SDK (@weavetab/sdk).`));
|
|
458
|
+
console.log(pc.dim("To scaffold a new plugin: ") + pc.cyan("npx @weavetab/sdk init <name>"));
|
|
459
|
+
console.log(pc.dim("To build/validate a plugin: ") + pc.cyan("npx @weavetab/sdk build"));
|
|
460
|
+
console.log(pc.dim("SDK documentation: ") + pc.cyan("https://github.com/weavetab/sdk\n"));
|
|
1106
461
|
return;
|
|
1107
462
|
}
|
|
1108
463
|
if (subcmd === "add" || subcmd === "install" || subcmd === "i") {
|
|
1109
|
-
await runPluginAdd(
|
|
464
|
+
await runPluginAdd(cleanArgs[1], cleanArgs.slice(2));
|
|
1110
465
|
return;
|
|
1111
466
|
}
|
|
1112
467
|
if (subcmd === "browse" || subcmd === "explore") {
|
|
@@ -1114,7 +469,7 @@ export async function runPluginCli(args) {
|
|
|
1114
469
|
return;
|
|
1115
470
|
}
|
|
1116
471
|
if (subcmd === "search" || subcmd === "find") {
|
|
1117
|
-
await runPluginSearch(
|
|
472
|
+
await runPluginSearch(cleanArgs[1]);
|
|
1118
473
|
return;
|
|
1119
474
|
}
|
|
1120
475
|
if (subcmd === "list" || subcmd === "ls") {
|
|
@@ -1122,13 +477,13 @@ export async function runPluginCli(args) {
|
|
|
1122
477
|
return;
|
|
1123
478
|
}
|
|
1124
479
|
if (subcmd === "remove" || subcmd === "rm" || subcmd === "uninstall") {
|
|
1125
|
-
await runPluginRemove(
|
|
480
|
+
await runPluginRemove(cleanArgs[1], cleanArgs.slice(2));
|
|
1126
481
|
return;
|
|
1127
482
|
}
|
|
1128
483
|
if (subcmd === "verify" || subcmd === "check") {
|
|
1129
|
-
await runPluginVerify(
|
|
484
|
+
await runPluginVerify(cleanArgs[1]);
|
|
1130
485
|
return;
|
|
1131
486
|
}
|
|
1132
487
|
console.log(pc.red(`[ERROR] Unknown plugin subcommand: "${subcmd}"`));
|
|
1133
|
-
console.log(pc.dim("Run '
|
|
488
|
+
console.log(pc.dim("Run 'weavetab plugin --help' to see available commands."));
|
|
1134
489
|
}
|