@keak/webmcp-core 0.1.0 → 0.1.1
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/README.md +88 -6
- package/bin/webmcp.mjs +7 -0
- package/dist/cli/commands/export.d.ts +2 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +88 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/generate.d.ts +2 -0
- package/dist/cli/commands/generate.d.ts.map +1 -0
- package/dist/cli/commands/generate.js +130 -0
- package/dist/cli/commands/generate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +130 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/scan.d.ts +2 -0
- package/dist/cli/commands/scan.d.ts.map +1 -0
- package/dist/cli/commands/scan.js +76 -0
- package/dist/cli/commands/scan.js.map +1 -0
- package/dist/cli/framework/config-writer.d.ts +30 -0
- package/dist/cli/framework/config-writer.d.ts.map +1 -0
- package/dist/cli/framework/config-writer.js +45 -0
- package/dist/cli/framework/config-writer.js.map +1 -0
- package/dist/cli/framework/detect.d.ts +8 -0
- package/dist/cli/framework/detect.d.ts.map +1 -0
- package/dist/cli/framework/detect.js +56 -0
- package/dist/cli/framework/detect.js.map +1 -0
- package/dist/cli/framework/presets.d.ts +11 -0
- package/dist/cli/framework/presets.d.ts.map +1 -0
- package/dist/cli/framework/presets.js +73 -0
- package/dist/cli/framework/presets.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +78 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ui/banner.d.ts +2 -0
- package/dist/cli/ui/banner.d.ts.map +1 -0
- package/dist/cli/ui/banner.js +14 -0
- package/dist/cli/ui/banner.js.map +1 -0
- package/dist/cli/ui/logger.d.ts +9 -0
- package/dist/cli/ui/logger.d.ts.map +1 -0
- package/dist/cli/ui/logger.js +16 -0
- package/dist/cli/ui/logger.js.map +1 -0
- package/dist/cli/ui/spinner.d.ts +3 -0
- package/dist/cli/ui/spinner.d.ts.map +1 -0
- package/dist/cli/ui/spinner.js +11 -0
- package/dist/cli/ui/spinner.js.map +1 -0
- package/dist/cli/ui/table.d.ts +4 -0
- package/dist/cli/ui/table.d.ts.map +1 -0
- package/dist/cli/ui/table.js +87 -0
- package/dist/cli/ui/table.js.map +1 -0
- package/dist/cli/util/args.d.ts +11 -0
- package/dist/cli/util/args.d.ts.map +1 -0
- package/dist/cli/util/args.js +30 -0
- package/dist/cli/util/args.js.map +1 -0
- package/dist/cli/util/env.d.ts +3 -0
- package/dist/cli/util/env.d.ts.map +1 -0
- package/dist/cli/util/env.js +27 -0
- package/dist/cli/util/env.js.map +1 -0
- package/dist/cli/util/version.d.ts +2 -0
- package/dist/cli/util/version.d.ts.map +1 -0
- package/dist/cli/util/version.js +29 -0
- package/dist/cli/util/version.js.map +1 -0
- package/dist/config.d.ts +10 -10
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/exporter/html-embed.d.ts +6 -0
- package/dist/exporter/html-embed.d.ts.map +1 -0
- package/dist/exporter/html-embed.js +123 -0
- package/dist/exporter/html-embed.js.map +1 -0
- package/dist/exporter/react-hook.d.ts +6 -0
- package/dist/exporter/react-hook.d.ts.map +1 -0
- package/dist/exporter/react-hook.js +158 -0
- package/dist/exporter/react-hook.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/scanner/browser.d.ts +13 -4
- package/dist/scanner/browser.d.ts.map +1 -1
- package/dist/scanner/browser.js +10 -3
- package/dist/scanner/browser.js.map +1 -1
- package/dist/synthesizer/llm-client.d.ts +2 -1
- package/dist/synthesizer/llm-client.d.ts.map +1 -1
- package/dist/synthesizer/llm-client.js +133 -2
- package/dist/synthesizer/llm-client.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -13,14 +13,74 @@ Auto-generate [WebMCP](https://nicholasc.au/2025/05/02/webmcp.html) tool definit
|
|
|
13
13
|
npm install @keak/webmcp-core
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Playwright is an optional peer dependency — only required
|
|
16
|
+
Playwright is an optional peer dependency — only required for scanning:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
19
|
npm install playwright
|
|
20
20
|
npx playwright install chromium
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## CLI
|
|
24
|
+
|
|
25
|
+
The fastest way to get started. Works with Next.js, React, Vue, Svelte, Vite, Shopify, Astro, and plain HTML.
|
|
26
|
+
|
|
27
|
+
### `webmcp init`
|
|
28
|
+
|
|
29
|
+
Interactive project setup. Detects your framework, creates `webmcp.config.json`, and adds an npm script.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx @keak/webmcp-core init
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### `webmcp generate <url>`
|
|
36
|
+
|
|
37
|
+
Scan a URL and generate tool definitions in one step.
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @keak/webmcp-core generate https://example.com
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Options:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
--format <format> Output format: snippet, react-hook, html-embed, manifest, userscript, yaml
|
|
47
|
+
--output <dir> Output directory (default: auto-detected from framework)
|
|
48
|
+
--lang <js|ts> Output language (default: ts if tsconfig.json exists)
|
|
49
|
+
--depth <n> Crawl depth (default: 2)
|
|
50
|
+
--headless Run browser in headless mode
|
|
51
|
+
--timeout <ms> Page timeout in milliseconds (default: 30000)
|
|
52
|
+
--cookie <string> Cookie string for authenticated pages
|
|
53
|
+
--api-key <key> OpenAI or Anthropic API key for AI enrichment
|
|
54
|
+
--model <model> AI model to use (default: gpt-4o-mini or claude-sonnet-4-20250514)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `webmcp scan <url>`
|
|
58
|
+
|
|
59
|
+
Scan only — saves raw results to `.webmcp/scan.json` for later export.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx @keak/webmcp-core scan https://example.com
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### `webmcp export`
|
|
66
|
+
|
|
67
|
+
Export tool definitions from a previous scan.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx @keak/webmcp-core export --format=react-hook
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### AI Enrichment (BYOK)
|
|
74
|
+
|
|
75
|
+
Pass your own OpenAI or Anthropic API key to improve tool names, descriptions, and field documentation. The provider is auto-detected from the key prefix (`sk-ant-*` for Anthropic, otherwise OpenAI).
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx @keak/webmcp-core generate https://example.com --api-key=sk-...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
API keys are never stored in config files. You can also set them via environment variables: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or `WEBMCP_API_KEY`.
|
|
82
|
+
|
|
83
|
+
## Quick Start (Programmatic)
|
|
24
84
|
|
|
25
85
|
```ts
|
|
26
86
|
import { generateToolDefinitions } from "@keak/webmcp-core";
|
|
@@ -38,12 +98,14 @@ for (const tool of tools) {
|
|
|
38
98
|
|
|
39
99
|
## Features
|
|
40
100
|
|
|
101
|
+
- **CLI with framework detection** — Auto-detects Next.js, React, Vue, Svelte, Vite, Shopify, Astro
|
|
41
102
|
- **Page scanning** — BFS crawl with Playwright, capturing forms, buttons, links, and network calls
|
|
42
103
|
- **Action extraction** — Identifies form submissions, API calls, click flows, and route changes
|
|
43
104
|
- **Tool synthesis** — Clusters related actions into named, described tool definitions with input schemas
|
|
44
105
|
- **Safety classification** — Tags each tool as `read`, `write`, or `danger` based on its behavior
|
|
106
|
+
- **AI enrichment** — BYOK support for OpenAI and Anthropic to improve tool quality
|
|
45
107
|
- **Linting** — Validates naming conventions, descriptions, schemas, and safety annotations
|
|
46
|
-
- **Multiple export formats** —
|
|
108
|
+
- **Multiple export formats** — Snippets, React hooks, HTML embeds, JSON manifests, userscripts, YAML
|
|
47
109
|
|
|
48
110
|
## API
|
|
49
111
|
|
|
@@ -85,8 +147,8 @@ const tools = proposeTools(scanResult, { minConfidence: 0.5 });
|
|
|
85
147
|
Export tool definitions in a specific format.
|
|
86
148
|
|
|
87
149
|
```ts
|
|
88
|
-
const result = exportTools(tools, "
|
|
89
|
-
fs.writeFileSync(
|
|
150
|
+
const result = exportTools(tools, "react-hook", { domain: "example.com" });
|
|
151
|
+
fs.writeFileSync(result.files[0].filename, result.files[0].content);
|
|
90
152
|
```
|
|
91
153
|
|
|
92
154
|
### `lintTools(tools)`
|
|
@@ -106,14 +168,34 @@ console.log(`${summary.errors} errors, ${summary.warnings} warnings`);
|
|
|
106
168
|
| Format | Output | Use Case |
|
|
107
169
|
|--------|--------|----------|
|
|
108
170
|
| `snippet` | `webmcp.tools.ts` | Drop-in `navigator.modelContext.registerTool()` code |
|
|
171
|
+
| `react-hook` | `webmcp.hooks.tsx` | `useWebMCPTools()` React hook with cleanup |
|
|
172
|
+
| `html-embed` | `webmcp.embed.html` | `<script>` tag for any HTML page |
|
|
109
173
|
| `manifest` | `webmcp.manifest.json` | Platform upload / API integration |
|
|
110
174
|
| `userscript` | `webmcp.*.user.js` | Tampermonkey / Greasemonkey script |
|
|
111
175
|
| `yaml` | `webmcp.tools.yaml` | Human-readable config |
|
|
112
176
|
|
|
177
|
+
## Config File
|
|
178
|
+
|
|
179
|
+
Running `webmcp init` creates a `webmcp.config.json`:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"baseUrl": "https://example.com",
|
|
184
|
+
"framework": "next",
|
|
185
|
+
"output": { "format": "snippet", "lang": "ts", "outDir": "public" },
|
|
186
|
+
"scan": { "depth": 2, "timeout": 30000, "headless": true, "ignore": [] },
|
|
187
|
+
"ai": { "provider": "openai", "model": "gpt-4o-mini" },
|
|
188
|
+
"auth": { "method": "none" }
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
CLI flags override config values. API keys are resolved from environment variables, never stored in config.
|
|
193
|
+
|
|
113
194
|
## Architecture
|
|
114
195
|
|
|
115
196
|
```
|
|
116
197
|
src/
|
|
198
|
+
├── cli/ CLI commands, framework detection, UI utilities
|
|
117
199
|
├── scanner/ Playwright-based page crawling and DOM capture
|
|
118
200
|
├── extractor/ Action extraction (forms, APIs, clicks, routes)
|
|
119
201
|
├── synthesizer/ Clustering, naming, description, safety, schemas
|
|
@@ -122,7 +204,7 @@ src/
|
|
|
122
204
|
└── utils/ Validation schemas and PII redaction
|
|
123
205
|
```
|
|
124
206
|
|
|
125
|
-
**Pipeline:** `scanUrl`
|
|
207
|
+
**Pipeline:** `scanUrl` -> extractors -> `clusterActions` -> `ToolSpec[]` -> `exportTools`
|
|
126
208
|
|
|
127
209
|
## Tool Definition Shape
|
|
128
210
|
|
package/bin/webmcp.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"AAcA,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoFjE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.exportCommand = exportCommand;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const args_js_1 = require("../util/args.js");
|
|
11
|
+
const version_js_1 = require("../util/version.js");
|
|
12
|
+
const banner_js_1 = require("../ui/banner.js");
|
|
13
|
+
const spinner_js_1 = require("../ui/spinner.js");
|
|
14
|
+
const logger_js_1 = require("../ui/logger.js");
|
|
15
|
+
const table_js_1 = require("../ui/table.js");
|
|
16
|
+
const config_writer_js_1 = require("../framework/config-writer.js");
|
|
17
|
+
const SCAN_PATH = (0, node_path_1.join)(".webmcp", "scan.json");
|
|
18
|
+
async function exportCommand(args) {
|
|
19
|
+
const { values, positionals } = (0, args_js_1.parseCommandArgs)(args);
|
|
20
|
+
if (values.help) {
|
|
21
|
+
console.log(`
|
|
22
|
+
${chalk_1.default.bold("webmcp export")} — Export tool definitions from saved scan data
|
|
23
|
+
|
|
24
|
+
${chalk_1.default.dim("Usage:")}
|
|
25
|
+
webmcp export [scan-file] [options]
|
|
26
|
+
|
|
27
|
+
If no file is given, reads from .webmcp/scan.json (created by "webmcp scan").
|
|
28
|
+
`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
(0, banner_js_1.printBanner)((0, version_js_1.getVersion)());
|
|
32
|
+
const config = (0, config_writer_js_1.loadConfig)();
|
|
33
|
+
const scanFile = positionals[0] ?? SCAN_PATH;
|
|
34
|
+
if (!(0, node_fs_1.existsSync)(scanFile)) {
|
|
35
|
+
logger_js_1.log.error(`Scan data not found at ${chalk_1.default.cyan(scanFile)}`);
|
|
36
|
+
logger_js_1.log.info('Run "webmcp scan <url>" first to create scan data.');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const spinner = (0, spinner_js_1.createSpinner)("Loading scan data...");
|
|
40
|
+
spinner.start();
|
|
41
|
+
let scanResult;
|
|
42
|
+
try {
|
|
43
|
+
scanResult = JSON.parse((0, node_fs_1.readFileSync)(scanFile, "utf-8"));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
spinner.fail("Failed to parse scan data");
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
spinner.succeed(`Loaded scan from ${chalk_1.default.cyan(scanResult.metadata.baseUrl)}`);
|
|
50
|
+
const proposeSpinner = (0, spinner_js_1.createSpinner)("Proposing tool definitions...");
|
|
51
|
+
proposeSpinner.start();
|
|
52
|
+
const { proposeTools, exportTools, lintTools } = await import("../../index.js");
|
|
53
|
+
const minConfidence = values["min-confidence"]
|
|
54
|
+
? parseFloat(values["min-confidence"])
|
|
55
|
+
: 0.5;
|
|
56
|
+
const tools = proposeTools(scanResult, { minConfidence });
|
|
57
|
+
proposeSpinner.succeed(`Proposed ${tools.length} tool${tools.length !== 1 ? "s" : ""}`);
|
|
58
|
+
if (tools.length === 0) {
|
|
59
|
+
logger_js_1.log.warn("No tools found in scan data.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const format = values.format ?? config?.output.format ?? "snippet";
|
|
63
|
+
const lang = values.lang ?? config?.output.lang ?? "ts";
|
|
64
|
+
const outDir = values.output ?? config?.output.outDir ?? "./webmcp-output";
|
|
65
|
+
let domain;
|
|
66
|
+
try {
|
|
67
|
+
domain = new URL(scanResult.metadata.baseUrl).hostname;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
domain = "unknown";
|
|
71
|
+
}
|
|
72
|
+
const exportSpinner = (0, spinner_js_1.createSpinner)(`Exporting as ${chalk_1.default.cyan(format)}...`);
|
|
73
|
+
exportSpinner.start();
|
|
74
|
+
const result = exportTools(tools, format, { lang, domain });
|
|
75
|
+
(0, node_fs_1.mkdirSync)(outDir, { recursive: true });
|
|
76
|
+
for (const file of result.files) {
|
|
77
|
+
(0, node_fs_1.writeFileSync)((0, node_path_1.join)(outDir, file.name), file.content, "utf-8");
|
|
78
|
+
}
|
|
79
|
+
exportSpinner.succeed(`Exported to ${chalk_1.default.cyan(outDir + "/")}`);
|
|
80
|
+
const lintResults = lintTools(tools);
|
|
81
|
+
(0, table_js_1.printToolsTable)(tools);
|
|
82
|
+
(0, table_js_1.printLintSummary)(lintResults);
|
|
83
|
+
for (const file of result.files) {
|
|
84
|
+
logger_js_1.log.info(` ${chalk_1.default.dim("→")} ${(0, node_path_1.join)(outDir, file.name)}`);
|
|
85
|
+
}
|
|
86
|
+
logger_js_1.log.blank();
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/cli/commands/export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"AAaA,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAkInE"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateCommand = generateCommand;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const args_js_1 = require("../util/args.js");
|
|
11
|
+
const env_js_1 = require("../util/env.js");
|
|
12
|
+
const version_js_1 = require("../util/version.js");
|
|
13
|
+
const banner_js_1 = require("../ui/banner.js");
|
|
14
|
+
const spinner_js_1 = require("../ui/spinner.js");
|
|
15
|
+
const logger_js_1 = require("../ui/logger.js");
|
|
16
|
+
const table_js_1 = require("../ui/table.js");
|
|
17
|
+
const config_writer_js_1 = require("../framework/config-writer.js");
|
|
18
|
+
async function generateCommand(args) {
|
|
19
|
+
const { values, positionals } = (0, args_js_1.parseCommandArgs)(args);
|
|
20
|
+
if (values.help) {
|
|
21
|
+
console.log(`
|
|
22
|
+
${chalk_1.default.bold("webmcp generate")} <url> — Scan a URL and generate tool definitions
|
|
23
|
+
|
|
24
|
+
${chalk_1.default.dim("Usage:")}
|
|
25
|
+
webmcp generate <url> [options]
|
|
26
|
+
|
|
27
|
+
If no URL is given, reads from webmcp.config.json.
|
|
28
|
+
`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
(0, banner_js_1.printBanner)((0, version_js_1.getVersion)());
|
|
32
|
+
const config = (0, config_writer_js_1.loadConfig)();
|
|
33
|
+
const url = positionals[0] ?? config?.baseUrl;
|
|
34
|
+
if (!url) {
|
|
35
|
+
logger_js_1.log.error("No URL provided. Usage: webmcp generate <url>");
|
|
36
|
+
logger_js_1.log.info('Or run "webmcp init" to create a config file.');
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const format = values.format ?? config?.output.format ?? "snippet";
|
|
40
|
+
const lang = values.lang ?? config?.output.lang ?? "ts";
|
|
41
|
+
const depth = values.depth ? parseInt(values.depth, 10) : config?.scan.depth ?? 2;
|
|
42
|
+
const headless = (values.headless === true) || (config?.scan.headless ?? true);
|
|
43
|
+
const timeout = values.timeout ? parseInt(values.timeout, 10) : config?.scan.timeout ?? 30000;
|
|
44
|
+
const outDir = values.output ?? config?.output.outDir ?? "./webmcp-output";
|
|
45
|
+
const apiKey = (0, env_js_1.resolveApiKey)(values);
|
|
46
|
+
// Step 1: Scan
|
|
47
|
+
const scanSpinner = (0, spinner_js_1.createSpinner)(`Scanning ${chalk_1.default.cyan(url)}...`);
|
|
48
|
+
scanSpinner.start();
|
|
49
|
+
let scanUrl;
|
|
50
|
+
try {
|
|
51
|
+
const mod = await import("../../index.js");
|
|
52
|
+
scanUrl = mod.scanUrl;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
scanSpinner.fail("Playwright not installed");
|
|
56
|
+
logger_js_1.log.blank();
|
|
57
|
+
logger_js_1.log.error("Playwright is required for scanning. Install it with:");
|
|
58
|
+
console.log(chalk_1.default.cyan(" npm install playwright && npx playwright install chromium"));
|
|
59
|
+
logger_js_1.log.blank();
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
const scanResult = await scanUrl({
|
|
63
|
+
url,
|
|
64
|
+
depth,
|
|
65
|
+
headless,
|
|
66
|
+
timeout,
|
|
67
|
+
onProgress: (event) => {
|
|
68
|
+
if (event.type === "page_visited") {
|
|
69
|
+
scanSpinner.text = `Scanned ${event.url} (${event.formsFound} forms, ${event.buttonsFound} buttons)`;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
scanSpinner.succeed(`Scanned ${scanResult.metadata.pagesVisited} page${scanResult.metadata.pagesVisited !== 1 ? "s" : ""}`);
|
|
74
|
+
// Step 2: Propose tools
|
|
75
|
+
const proposeSpinner = (0, spinner_js_1.createSpinner)("Proposing tool definitions...");
|
|
76
|
+
proposeSpinner.start();
|
|
77
|
+
const { proposeTools } = await import("../../index.js");
|
|
78
|
+
const minConfidence = values["min-confidence"]
|
|
79
|
+
? parseFloat(values["min-confidence"])
|
|
80
|
+
: 0.5;
|
|
81
|
+
let tools = proposeTools(scanResult, { minConfidence });
|
|
82
|
+
proposeSpinner.succeed(`Proposed ${tools.length} tool${tools.length !== 1 ? "s" : ""}`);
|
|
83
|
+
if (tools.length === 0) {
|
|
84
|
+
logger_js_1.log.warn("No tools found. Try scanning a different URL or lowering --min-confidence.");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Step 3: AI Enrichment
|
|
88
|
+
if (apiKey) {
|
|
89
|
+
const aiSpinner = (0, spinner_js_1.createSpinner)("Enriching with AI...");
|
|
90
|
+
aiSpinner.start();
|
|
91
|
+
const { enhanceWithLlm } = await import("../../synthesizer/llm-client.js");
|
|
92
|
+
const provider = (0, env_js_1.resolveProvider)(apiKey, values);
|
|
93
|
+
const model = values.model ?? config?.ai?.model;
|
|
94
|
+
tools = await enhanceWithLlm(tools, scanResult.actions, {
|
|
95
|
+
apiKey,
|
|
96
|
+
provider,
|
|
97
|
+
model,
|
|
98
|
+
});
|
|
99
|
+
aiSpinner.succeed("AI enrichment complete");
|
|
100
|
+
}
|
|
101
|
+
// Step 4: Lint
|
|
102
|
+
const { lintTools } = await import("../../index.js");
|
|
103
|
+
const lintResults = lintTools(tools);
|
|
104
|
+
// Step 5: Export
|
|
105
|
+
const exportSpinner = (0, spinner_js_1.createSpinner)(`Exporting as ${chalk_1.default.cyan(format)}...`);
|
|
106
|
+
exportSpinner.start();
|
|
107
|
+
const { exportTools } = await import("../../index.js");
|
|
108
|
+
let domain;
|
|
109
|
+
try {
|
|
110
|
+
domain = new URL(url).hostname;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
domain = "unknown";
|
|
114
|
+
}
|
|
115
|
+
const result = exportTools(tools, format, { lang, domain });
|
|
116
|
+
(0, node_fs_1.mkdirSync)(outDir, { recursive: true });
|
|
117
|
+
for (const file of result.files) {
|
|
118
|
+
const filepath = (0, node_path_1.join)(outDir, file.name);
|
|
119
|
+
(0, node_fs_1.writeFileSync)(filepath, file.content, "utf-8");
|
|
120
|
+
}
|
|
121
|
+
exportSpinner.succeed(`Exported to ${chalk_1.default.cyan(outDir + "/")}`);
|
|
122
|
+
// Step 6: Summary
|
|
123
|
+
(0, table_js_1.printToolsTable)(tools);
|
|
124
|
+
(0, table_js_1.printLintSummary)(lintResults);
|
|
125
|
+
for (const file of result.files) {
|
|
126
|
+
logger_js_1.log.info(` ${chalk_1.default.dim("→")} ${(0, node_path_1.join)(outDir, file.name)}`);
|
|
127
|
+
}
|
|
128
|
+
logger_js_1.log.blank();
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/cli/commands/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"AAUA,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAqIhE"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.initCommand = initCommand;
|
|
7
|
+
const prompts_1 = require("@inquirer/prompts");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const banner_js_1 = require("../ui/banner.js");
|
|
10
|
+
const logger_js_1 = require("../ui/logger.js");
|
|
11
|
+
const version_js_1 = require("../util/version.js");
|
|
12
|
+
const detect_js_1 = require("../framework/detect.js");
|
|
13
|
+
const presets_js_1 = require("../framework/presets.js");
|
|
14
|
+
const config_writer_js_1 = require("../framework/config-writer.js");
|
|
15
|
+
async function initCommand(_args) {
|
|
16
|
+
(0, banner_js_1.printBanner)((0, version_js_1.getVersion)());
|
|
17
|
+
if ((0, config_writer_js_1.configExists)()) {
|
|
18
|
+
const overwrite = await (0, prompts_1.confirm)({
|
|
19
|
+
message: "webmcp.config.json already exists. Overwrite?",
|
|
20
|
+
default: false,
|
|
21
|
+
});
|
|
22
|
+
if (!overwrite) {
|
|
23
|
+
logger_js_1.log.info("Init cancelled.");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
const detection = (0, detect_js_1.detectFramework)();
|
|
28
|
+
const preset = (0, presets_js_1.getPreset)(detection.framework);
|
|
29
|
+
logger_js_1.log.info(`Detected framework: ${chalk_1.default.cyan(preset.label)}`);
|
|
30
|
+
if (detection.hasTypeScript)
|
|
31
|
+
logger_js_1.log.info("TypeScript: " + chalk_1.default.green("yes"));
|
|
32
|
+
logger_js_1.log.blank();
|
|
33
|
+
const frameworkChoices = [
|
|
34
|
+
{ value: detection.framework, name: `${preset.label} (detected)` },
|
|
35
|
+
{ value: "next", name: "Next.js" },
|
|
36
|
+
{ value: "react-vite", name: "React + Vite" },
|
|
37
|
+
{ value: "vue", name: "Vue.js" },
|
|
38
|
+
{ value: "svelte", name: "SvelteKit" },
|
|
39
|
+
{ value: "vite", name: "Vite" },
|
|
40
|
+
{ value: "shopify", name: "Shopify" },
|
|
41
|
+
{ value: "astro", name: "Astro" },
|
|
42
|
+
{ value: "html", name: "Plain HTML" },
|
|
43
|
+
];
|
|
44
|
+
const framework = await (0, prompts_1.select)({
|
|
45
|
+
message: "Confirm your framework:",
|
|
46
|
+
default: detection.framework,
|
|
47
|
+
choices: frameworkChoices.filter((c, i, arr) => i === 0 || c.value !== arr[0].value),
|
|
48
|
+
});
|
|
49
|
+
const selectedPreset = (0, presets_js_1.getPreset)(framework);
|
|
50
|
+
const baseUrl = await (0, prompts_1.input)({
|
|
51
|
+
message: "Base URL to scan:",
|
|
52
|
+
validate: (val) => {
|
|
53
|
+
try {
|
|
54
|
+
new URL(val);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return "Enter a valid URL (e.g., https://example.com)";
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
const format = await (0, prompts_1.select)({
|
|
63
|
+
message: "Output format:",
|
|
64
|
+
default: selectedPreset.defaultFormat,
|
|
65
|
+
choices: [
|
|
66
|
+
{ value: "snippet", name: "snippet — JavaScript/TypeScript file" },
|
|
67
|
+
{ value: "react-hook", name: "react-hook — React useWebMCPTools() hook" },
|
|
68
|
+
{ value: "html-embed", name: "html-embed — <script> tag for any HTML page" },
|
|
69
|
+
{ value: "manifest", name: "manifest — JSON manifest" },
|
|
70
|
+
{ value: "userscript", name: "userscript — Tampermonkey/Greasemonkey" },
|
|
71
|
+
{ value: "yaml", name: "yaml — YAML config" },
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
const lang = detection.hasTypeScript ? "ts" : "js";
|
|
75
|
+
const outDir = selectedPreset.defaultOutDir;
|
|
76
|
+
let aiProvider;
|
|
77
|
+
let aiModel;
|
|
78
|
+
const useAi = await (0, prompts_1.confirm)({
|
|
79
|
+
message: "Enable AI enrichment? (requires an OpenAI or Anthropic API key)",
|
|
80
|
+
default: false,
|
|
81
|
+
});
|
|
82
|
+
if (useAi) {
|
|
83
|
+
aiProvider = await (0, prompts_1.select)({
|
|
84
|
+
message: "AI provider:",
|
|
85
|
+
choices: [
|
|
86
|
+
{ value: "openai", name: "OpenAI" },
|
|
87
|
+
{ value: "anthropic", name: "Anthropic" },
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
const key = await (0, prompts_1.password)({
|
|
91
|
+
message: `${aiProvider === "openai" ? "OpenAI" : "Anthropic"} API key:`,
|
|
92
|
+
});
|
|
93
|
+
if (key) {
|
|
94
|
+
const envVar = aiProvider === "openai" ? "OPENAI_API_KEY" : "ANTHROPIC_API_KEY";
|
|
95
|
+
logger_js_1.log.info(`Set ${chalk_1.default.cyan(envVar)}=${chalk_1.default.dim("sk-...")} in your environment.`);
|
|
96
|
+
logger_js_1.log.info("API keys are not stored in the config file.");
|
|
97
|
+
}
|
|
98
|
+
aiModel = aiProvider === "openai" ? "gpt-4o-mini" : "claude-sonnet-4-20250514";
|
|
99
|
+
}
|
|
100
|
+
(0, config_writer_js_1.writeConfig)({
|
|
101
|
+
baseUrl,
|
|
102
|
+
framework,
|
|
103
|
+
output: { format, lang, outDir },
|
|
104
|
+
scan: { depth: 2, timeout: 30000, headless: true, ignore: [] },
|
|
105
|
+
ai: aiProvider ? { provider: aiProvider, model: aiModel } : undefined,
|
|
106
|
+
auth: { method: "none" },
|
|
107
|
+
});
|
|
108
|
+
logger_js_1.log.success("Created " + chalk_1.default.cyan("webmcp.config.json"));
|
|
109
|
+
const addScript = await (0, prompts_1.confirm)({
|
|
110
|
+
message: 'Add "webmcp:generate" script to package.json?',
|
|
111
|
+
default: true,
|
|
112
|
+
});
|
|
113
|
+
if (addScript) {
|
|
114
|
+
const added = (0, config_writer_js_1.addNpmScript)("webmcp:generate", "webmcp generate");
|
|
115
|
+
if (added) {
|
|
116
|
+
logger_js_1.log.success('Added "webmcp:generate" to package.json scripts');
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
logger_js_1.log.warn("Could not add script — no package.json found");
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
logger_js_1.log.blank();
|
|
123
|
+
logger_js_1.log.success("WebMCP is ready!");
|
|
124
|
+
logger_js_1.log.blank();
|
|
125
|
+
console.log(chalk_1.default.dim(" Next steps:"));
|
|
126
|
+
console.log(` ${chalk_1.default.cyan("npx @keak/webmcp-core generate")} — Generate tool definitions`);
|
|
127
|
+
console.log(` ${chalk_1.default.cyan("npm run webmcp:generate")} — Or use the npm script`);
|
|
128
|
+
logger_js_1.log.blank();
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/scan.ts"],"names":[],"mappings":"AAYA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAoE/D"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.scanCommand = scanCommand;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_path_1 = require("node:path");
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const args_js_1 = require("../util/args.js");
|
|
11
|
+
const version_js_1 = require("../util/version.js");
|
|
12
|
+
const banner_js_1 = require("../ui/banner.js");
|
|
13
|
+
const spinner_js_1 = require("../ui/spinner.js");
|
|
14
|
+
const logger_js_1 = require("../ui/logger.js");
|
|
15
|
+
const config_writer_js_1 = require("../framework/config-writer.js");
|
|
16
|
+
const WEBMCP_DIR = ".webmcp";
|
|
17
|
+
async function scanCommand(args) {
|
|
18
|
+
const { values, positionals } = (0, args_js_1.parseCommandArgs)(args);
|
|
19
|
+
if (values.help) {
|
|
20
|
+
console.log(`
|
|
21
|
+
${chalk_1.default.bold("webmcp scan")} <url> — Scan a URL and save raw results
|
|
22
|
+
|
|
23
|
+
${chalk_1.default.dim("Usage:")}
|
|
24
|
+
webmcp scan <url> [options]
|
|
25
|
+
|
|
26
|
+
Results are saved to .webmcp/scan.json for later use with "webmcp export".
|
|
27
|
+
`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
(0, banner_js_1.printBanner)((0, version_js_1.getVersion)());
|
|
31
|
+
const config = (0, config_writer_js_1.loadConfig)();
|
|
32
|
+
const url = positionals[0] ?? config?.baseUrl;
|
|
33
|
+
if (!url) {
|
|
34
|
+
logger_js_1.log.error("No URL provided. Usage: webmcp scan <url>");
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const depth = values.depth ? parseInt(values.depth, 10) : config?.scan.depth ?? 2;
|
|
38
|
+
const headless = (values.headless === true) || (config?.scan.headless ?? true);
|
|
39
|
+
const timeout = values.timeout ? parseInt(values.timeout, 10) : config?.scan.timeout ?? 30000;
|
|
40
|
+
const spinner = (0, spinner_js_1.createSpinner)(`Scanning ${chalk_1.default.cyan(url)}...`);
|
|
41
|
+
spinner.start();
|
|
42
|
+
let scanUrl;
|
|
43
|
+
try {
|
|
44
|
+
const mod = await import("../../index.js");
|
|
45
|
+
scanUrl = mod.scanUrl;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
spinner.fail("Playwright not installed");
|
|
49
|
+
logger_js_1.log.blank();
|
|
50
|
+
logger_js_1.log.error("Playwright is required for scanning. Install it with:");
|
|
51
|
+
console.log(chalk_1.default.cyan(" npm install playwright && npx playwright install chromium"));
|
|
52
|
+
logger_js_1.log.blank();
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const scanResult = await scanUrl({
|
|
56
|
+
url,
|
|
57
|
+
depth,
|
|
58
|
+
headless,
|
|
59
|
+
timeout,
|
|
60
|
+
onProgress: (event) => {
|
|
61
|
+
if (event.type === "page_visited") {
|
|
62
|
+
spinner.text = `Scanned ${event.url} (${event.formsFound} forms, ${event.buttonsFound} buttons)`;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
spinner.succeed(`Scanned ${scanResult.metadata.pagesVisited} page${scanResult.metadata.pagesVisited !== 1 ? "s" : ""}`);
|
|
67
|
+
(0, node_fs_1.mkdirSync)(WEBMCP_DIR, { recursive: true });
|
|
68
|
+
const outPath = (0, node_path_1.join)(WEBMCP_DIR, "scan.json");
|
|
69
|
+
(0, node_fs_1.writeFileSync)(outPath, JSON.stringify(scanResult, null, 2), "utf-8");
|
|
70
|
+
logger_js_1.log.success(`Saved scan results to ${chalk_1.default.cyan(outPath)}`);
|
|
71
|
+
logger_js_1.log.info(`Found ${scanResult.pages.reduce((n, p) => n + p.forms.length, 0)} forms, ${scanResult.networkCalls.length} network calls`);
|
|
72
|
+
logger_js_1.log.blank();
|
|
73
|
+
logger_js_1.log.info(`Next: ${chalk_1.default.cyan("webmcp export")} to generate tool definitions from this scan.`);
|
|
74
|
+
logger_js_1.log.blank();
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../src/cli/commands/scan.ts"],"names":[],"mappings":"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"}
|