@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.
Files changed (87) hide show
  1. package/README.md +88 -6
  2. package/bin/webmcp.mjs +7 -0
  3. package/dist/cli/commands/export.d.ts +2 -0
  4. package/dist/cli/commands/export.d.ts.map +1 -0
  5. package/dist/cli/commands/export.js +88 -0
  6. package/dist/cli/commands/export.js.map +1 -0
  7. package/dist/cli/commands/generate.d.ts +2 -0
  8. package/dist/cli/commands/generate.d.ts.map +1 -0
  9. package/dist/cli/commands/generate.js +130 -0
  10. package/dist/cli/commands/generate.js.map +1 -0
  11. package/dist/cli/commands/init.d.ts +2 -0
  12. package/dist/cli/commands/init.d.ts.map +1 -0
  13. package/dist/cli/commands/init.js +130 -0
  14. package/dist/cli/commands/init.js.map +1 -0
  15. package/dist/cli/commands/scan.d.ts +2 -0
  16. package/dist/cli/commands/scan.d.ts.map +1 -0
  17. package/dist/cli/commands/scan.js +76 -0
  18. package/dist/cli/commands/scan.js.map +1 -0
  19. package/dist/cli/framework/config-writer.d.ts +30 -0
  20. package/dist/cli/framework/config-writer.d.ts.map +1 -0
  21. package/dist/cli/framework/config-writer.js +45 -0
  22. package/dist/cli/framework/config-writer.js.map +1 -0
  23. package/dist/cli/framework/detect.d.ts +8 -0
  24. package/dist/cli/framework/detect.d.ts.map +1 -0
  25. package/dist/cli/framework/detect.js +56 -0
  26. package/dist/cli/framework/detect.js.map +1 -0
  27. package/dist/cli/framework/presets.d.ts +11 -0
  28. package/dist/cli/framework/presets.d.ts.map +1 -0
  29. package/dist/cli/framework/presets.js +73 -0
  30. package/dist/cli/framework/presets.js.map +1 -0
  31. package/dist/cli/index.d.ts +2 -0
  32. package/dist/cli/index.d.ts.map +1 -0
  33. package/dist/cli/index.js +78 -0
  34. package/dist/cli/index.js.map +1 -0
  35. package/dist/cli/ui/banner.d.ts +2 -0
  36. package/dist/cli/ui/banner.d.ts.map +1 -0
  37. package/dist/cli/ui/banner.js +14 -0
  38. package/dist/cli/ui/banner.js.map +1 -0
  39. package/dist/cli/ui/logger.d.ts +9 -0
  40. package/dist/cli/ui/logger.d.ts.map +1 -0
  41. package/dist/cli/ui/logger.js +16 -0
  42. package/dist/cli/ui/logger.js.map +1 -0
  43. package/dist/cli/ui/spinner.d.ts +3 -0
  44. package/dist/cli/ui/spinner.d.ts.map +1 -0
  45. package/dist/cli/ui/spinner.js +11 -0
  46. package/dist/cli/ui/spinner.js.map +1 -0
  47. package/dist/cli/ui/table.d.ts +4 -0
  48. package/dist/cli/ui/table.d.ts.map +1 -0
  49. package/dist/cli/ui/table.js +87 -0
  50. package/dist/cli/ui/table.js.map +1 -0
  51. package/dist/cli/util/args.d.ts +11 -0
  52. package/dist/cli/util/args.d.ts.map +1 -0
  53. package/dist/cli/util/args.js +30 -0
  54. package/dist/cli/util/args.js.map +1 -0
  55. package/dist/cli/util/env.d.ts +3 -0
  56. package/dist/cli/util/env.d.ts.map +1 -0
  57. package/dist/cli/util/env.js +27 -0
  58. package/dist/cli/util/env.js.map +1 -0
  59. package/dist/cli/util/version.d.ts +2 -0
  60. package/dist/cli/util/version.d.ts.map +1 -0
  61. package/dist/cli/util/version.js +29 -0
  62. package/dist/cli/util/version.js.map +1 -0
  63. package/dist/config.d.ts +10 -10
  64. package/dist/config.js +2 -2
  65. package/dist/config.js.map +1 -1
  66. package/dist/exporter/html-embed.d.ts +6 -0
  67. package/dist/exporter/html-embed.d.ts.map +1 -0
  68. package/dist/exporter/html-embed.js +123 -0
  69. package/dist/exporter/html-embed.js.map +1 -0
  70. package/dist/exporter/react-hook.d.ts +6 -0
  71. package/dist/exporter/react-hook.d.ts.map +1 -0
  72. package/dist/exporter/react-hook.js +158 -0
  73. package/dist/exporter/react-hook.js.map +1 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +6 -0
  76. package/dist/index.js.map +1 -1
  77. package/dist/scanner/browser.d.ts +13 -4
  78. package/dist/scanner/browser.d.ts.map +1 -1
  79. package/dist/scanner/browser.js +10 -3
  80. package/dist/scanner/browser.js.map +1 -1
  81. package/dist/synthesizer/llm-client.d.ts +2 -1
  82. package/dist/synthesizer/llm-client.d.ts.map +1 -1
  83. package/dist/synthesizer/llm-client.js +133 -2
  84. package/dist/synthesizer/llm-client.js.map +1 -1
  85. package/dist/types.d.ts +2 -2
  86. package/dist/types.d.ts.map +1 -1
  87. 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 if you use `scanUrl()` or `generateToolDefinitions()`:
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
- ## Quick Start
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** — TypeScript snippets, JSON manifests, Tampermonkey userscripts, YAML configs
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, "manifest", { domain: "example.com" });
89
- fs.writeFileSync("webmcp.manifest.json", result.files[0].content);
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` extractors `clusterActions` `ToolSpec[]` `exportTools`
207
+ **Pipeline:** `scanUrl` -> extractors -> `clusterActions` -> `ToolSpec[]` -> `exportTools`
126
208
 
127
209
  ## Tool Definition Shape
128
210
 
package/bin/webmcp.mjs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { run } from "../dist/cli/index.js";
3
+
4
+ run(process.argv.slice(2)).catch((err) => {
5
+ console.error(err.message || err);
6
+ process.exit(1);
7
+ });
@@ -0,0 +1,2 @@
1
+ export declare function exportCommand(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=export.d.ts.map
@@ -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,2 @@
1
+ export declare function generateCommand(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=generate.d.ts.map
@@ -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,2 @@
1
+ export declare function initCommand(_args: string[]): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -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,2 @@
1
+ export declare function scanCommand(args: string[]): Promise<void>;
2
+ //# sourceMappingURL=scan.d.ts.map
@@ -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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"}