webmcp-codegen 0.3.1 → 0.3.3
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/dist/{chunk-I4ZL527H.js → chunk-EAKYM4YS.js} +2 -5
- package/dist/chunk-EAKYM4YS.js.map +1 -0
- package/dist/chunk-MUTXYBL6.js +1255 -0
- package/dist/chunk-MUTXYBL6.js.map +1 -0
- package/dist/cli.d.ts +32 -0
- package/dist/cli.js +234 -197
- package/dist/cli.js.map +1 -1
- package/dist/dev/server.d.ts +25 -0
- package/dist/dev/server.js +12 -0
- package/dist/dev/server.js.map +1 -0
- package/dist/generators/index.d.ts +1 -1
- package/dist/generators/index.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/sources/index.d.ts +1 -1
- package/dist/{types-DWUum51l.d.ts → types-DfK3AA5H.d.ts} +1 -1
- package/package.json +3 -3
- package/dist/chunk-CCVNYNJ5.js +0 -235
- package/dist/chunk-CCVNYNJ5.js.map +0 -1
- package/dist/chunk-I4ZL527H.js.map +0 -1
- package/dist/server-DWP6IHCS.js +0 -638
- package/dist/server-DWP6IHCS.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,25 +1,160 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
findSpecs,
|
|
4
|
-
loadDataFile,
|
|
5
4
|
resolveSetup,
|
|
6
|
-
saveDataFile
|
|
7
|
-
|
|
5
|
+
saveDataFile,
|
|
6
|
+
startDevServer
|
|
7
|
+
} from "./chunk-MUTXYBL6.js";
|
|
8
8
|
import {
|
|
9
|
+
CONFIG_FILE_NAMES,
|
|
9
10
|
runGenerate
|
|
10
11
|
} from "./chunk-MJQ5B6HB.js";
|
|
12
|
+
import "./chunk-EAKYM4YS.js";
|
|
11
13
|
import "./chunk-3LTHWIAP.js";
|
|
12
14
|
import "./chunk-FWSATV7C.js";
|
|
13
|
-
import "./chunk-I4ZL527H.js";
|
|
14
15
|
import "./chunk-KSQMJERY.js";
|
|
15
16
|
|
|
16
17
|
// src/cli.ts
|
|
17
|
-
import { existsSync
|
|
18
|
+
import { existsSync } from "fs";
|
|
18
19
|
import { writeFile as writeFile2 } from "fs/promises";
|
|
19
|
-
import { join as join2
|
|
20
|
-
import "readline/promises";
|
|
20
|
+
import { join as join2 } from "path";
|
|
21
21
|
import { parseArgs } from "util";
|
|
22
22
|
|
|
23
|
+
// src/cli-output.ts
|
|
24
|
+
var ESC = "\x1B[";
|
|
25
|
+
var RESET = `${ESC}0m`;
|
|
26
|
+
var BOLD = `${ESC}1m`;
|
|
27
|
+
var DIM = `${ESC}2m`;
|
|
28
|
+
var FG = {
|
|
29
|
+
red: `${ESC}31m`,
|
|
30
|
+
green: `${ESC}32m`,
|
|
31
|
+
yellow: `${ESC}33m`,
|
|
32
|
+
blue: `${ESC}34m`,
|
|
33
|
+
cyan: `${ESC}36m`,
|
|
34
|
+
gray: `${ESC}90m`
|
|
35
|
+
};
|
|
36
|
+
function c(color, text) {
|
|
37
|
+
return `${FG[color]}${text}${RESET}`;
|
|
38
|
+
}
|
|
39
|
+
function bold(text) {
|
|
40
|
+
return `${BOLD}${text}${RESET}`;
|
|
41
|
+
}
|
|
42
|
+
function dim(text) {
|
|
43
|
+
return `${DIM}${text}${RESET}`;
|
|
44
|
+
}
|
|
45
|
+
function summarizeFindings(findings) {
|
|
46
|
+
const counts = { auth: 0, admin: 0, pii: 0, postAsRead: 0, other: 0 };
|
|
47
|
+
for (const f of findings) {
|
|
48
|
+
const msg = f.message.toLowerCase();
|
|
49
|
+
if (msg.includes("sign-in") || msg.includes("auth") || msg.includes("session")) {
|
|
50
|
+
counts.auth++;
|
|
51
|
+
} else if (msg.includes("admin")) {
|
|
52
|
+
counts.admin++;
|
|
53
|
+
} else if (msg.includes("pii") || msg.includes("email")) {
|
|
54
|
+
counts.pii++;
|
|
55
|
+
} else if (msg.includes("post") && msg.includes("read")) {
|
|
56
|
+
counts.postAsRead++;
|
|
57
|
+
} else {
|
|
58
|
+
counts.other++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return counts;
|
|
62
|
+
}
|
|
63
|
+
function renderSummary(result, setup, _cwd, wiring) {
|
|
64
|
+
const { tools, findings, skipped } = result;
|
|
65
|
+
const reads = tools.filter((t) => t.sideEffect === "read").length;
|
|
66
|
+
const writes = tools.filter((t) => t.sideEffect === "write").length;
|
|
67
|
+
const destructives = tools.filter((t) => t.sideEffect === "destructive").length;
|
|
68
|
+
const enabled = tools.filter((t) => t.enabledByDefault).length;
|
|
69
|
+
const findingCounts = summarizeFindings(findings);
|
|
70
|
+
const totalFindings = findings.length;
|
|
71
|
+
console.log("");
|
|
72
|
+
console.log(` ${bold("webmcp-codegen")}`);
|
|
73
|
+
console.log(dim(` ${setup.label}`));
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log(` ${c("green", "\u2713")} ${bold(`${tools.length} tools generated`)}`);
|
|
76
|
+
console.log(dim(` ${enabled} ready to use, ${tools.length - enabled} start disabled`));
|
|
77
|
+
if (skipped.length > 0) {
|
|
78
|
+
console.log(dim(` ${skipped.length} skipped (webhooks and excluded endpoints)`));
|
|
79
|
+
}
|
|
80
|
+
console.log("");
|
|
81
|
+
if (totalFindings > 0) {
|
|
82
|
+
console.log(` ${c("yellow", "!")} ${bold(`${totalFindings} safety note${totalFindings === 1 ? "" : "s"}`)}`);
|
|
83
|
+
if (findingCounts.auth > 0) {
|
|
84
|
+
console.log(dim(` ${findingCounts.auth} auth endpoint${findingCounts.auth === 1 ? "" : "s"} disabled (agents shouldn't sign in)`));
|
|
85
|
+
}
|
|
86
|
+
if (findingCounts.admin > 0) {
|
|
87
|
+
console.log(dim(` ${findingCounts.admin} admin endpoint${findingCounts.admin === 1 ? "" : "s"} disabled (review each before enabling)`));
|
|
88
|
+
}
|
|
89
|
+
if (findingCounts.pii > 0) {
|
|
90
|
+
console.log(dim(` ${findingCounts.pii} endpoint${findingCounts.pii === 1 ? "" : "s"} may return personal data`));
|
|
91
|
+
}
|
|
92
|
+
if (findingCounts.postAsRead > 0) {
|
|
93
|
+
console.log(dim(` ${findingCounts.postAsRead} POST endpoint${findingCounts.postAsRead === 1 ? "" : "s"} treated as read-only (verify this is correct)`));
|
|
94
|
+
}
|
|
95
|
+
console.log(dim(` Run with --verbose to see all details`));
|
|
96
|
+
console.log("");
|
|
97
|
+
}
|
|
98
|
+
const outDir = setup.config.generate[0]?.outDir ?? "src/webmcp";
|
|
99
|
+
console.log(` ${c("cyan", "\u2192")} ${bold("Files")} ${outDir}`);
|
|
100
|
+
if (wiring && !wiring.alreadyWired) {
|
|
101
|
+
console.log(` ${c("cyan", "\u2192")} ${bold("Registration")} wired into your app`);
|
|
102
|
+
}
|
|
103
|
+
console.log("");
|
|
104
|
+
console.log(` ${bold("Next:")} ${c("cyan", "npx webmcp-codegen dev")}`);
|
|
105
|
+
console.log(dim(" Review your tools, edit descriptions, test them live"));
|
|
106
|
+
console.log("");
|
|
107
|
+
console.log(dim(` Docs: https://webmcp-codegen.vercel.app/docs`));
|
|
108
|
+
console.log("");
|
|
109
|
+
}
|
|
110
|
+
function renderVerbose(result, setup, _cwd) {
|
|
111
|
+
const { tools, findings, skipped } = result;
|
|
112
|
+
console.log("");
|
|
113
|
+
console.log(bold(`webmcp-codegen`));
|
|
114
|
+
console.log(dim(`${tools.length} tools from ${setup.label}`));
|
|
115
|
+
console.log("");
|
|
116
|
+
if (skipped.length > 0) {
|
|
117
|
+
console.log(c("gray", "Skipped:"));
|
|
118
|
+
for (const s of skipped) {
|
|
119
|
+
console.log(` ${dim(s.ref)}`);
|
|
120
|
+
console.log(` ${dim(s.reason)}`);
|
|
121
|
+
}
|
|
122
|
+
console.log("");
|
|
123
|
+
}
|
|
124
|
+
const byRisk = {
|
|
125
|
+
read: tools.filter((t) => t.sideEffect === "read"),
|
|
126
|
+
write: tools.filter((t) => t.sideEffect === "write"),
|
|
127
|
+
destructive: tools.filter((t) => t.sideEffect === "destructive")
|
|
128
|
+
};
|
|
129
|
+
const riskLabels = {
|
|
130
|
+
read: c("green", "Read-only"),
|
|
131
|
+
write: c("yellow", "Write"),
|
|
132
|
+
destructive: c("red", "Destructive")
|
|
133
|
+
};
|
|
134
|
+
for (const [risk, group] of Object.entries(byRisk)) {
|
|
135
|
+
if (group.length === 0) continue;
|
|
136
|
+
console.log(riskLabels[risk] ?? risk);
|
|
137
|
+
for (const tool of group) {
|
|
138
|
+
const status = tool.enabledByDefault ? "" : dim(" (disabled)");
|
|
139
|
+
console.log(` ${tool.name}${status}`);
|
|
140
|
+
if (tool.description) console.log(` ${dim(tool.description)}`);
|
|
141
|
+
}
|
|
142
|
+
console.log("");
|
|
143
|
+
}
|
|
144
|
+
if (findings.length > 0) {
|
|
145
|
+
console.log(bold("Safety notes:"));
|
|
146
|
+
for (const f of findings) {
|
|
147
|
+
const icon = f.level === "error" ? c("red", "\u2716") : c("yellow", "\u26A0");
|
|
148
|
+
const where = f.tool ? dim(` (${f.tool})`) : "";
|
|
149
|
+
console.log(` ${icon} ${f.message}${where}`);
|
|
150
|
+
}
|
|
151
|
+
console.log("");
|
|
152
|
+
}
|
|
153
|
+
console.log(dim(`Files: ${setup.config.generate[0]?.outDir ?? "src/webmcp"}`));
|
|
154
|
+
console.log(dim(`Docs: https://webmcp-codegen.vercel.app/docs`));
|
|
155
|
+
console.log("");
|
|
156
|
+
}
|
|
157
|
+
|
|
23
158
|
// src/wire.ts
|
|
24
159
|
import { readFile, writeFile } from "fs/promises";
|
|
25
160
|
import { dirname, join, relative } from "path";
|
|
@@ -151,38 +286,46 @@ async function firstExisting(paths) {
|
|
|
151
286
|
}
|
|
152
287
|
|
|
153
288
|
// src/cli.ts
|
|
154
|
-
var HELP = `
|
|
289
|
+
var HELP = `
|
|
290
|
+
webmcp-codegen \u2014 generate WebMCP tools from your OpenAPI spec
|
|
155
291
|
|
|
156
|
-
|
|
157
|
-
npx webmcp-codegen
|
|
158
|
-
npx webmcp-codegen generate Write the tool files, wire them up
|
|
292
|
+
Usage
|
|
293
|
+
npx webmcp-codegen [command] [flags]
|
|
159
294
|
|
|
160
|
-
Commands
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
dev Open the tools dashboard (list, edit, try tools)
|
|
295
|
+
Commands
|
|
296
|
+
generate Generate tool files from your spec (default when no command given)
|
|
297
|
+
dev Open the tools dashboard (list, describe, toggle, test)
|
|
298
|
+
init Write a codegen.config.mjs for full control
|
|
165
299
|
|
|
166
|
-
Flags
|
|
300
|
+
Flags
|
|
167
301
|
--spec PATH Which OpenAPI spec to use (auto-detected when omitted)
|
|
168
|
-
--out DIR Where
|
|
302
|
+
--out DIR Where tool files go (default: your web app's src/webmcp)
|
|
169
303
|
--dry-run Preview what would be written, write nothing
|
|
170
|
-
--
|
|
304
|
+
--verbose Show every tool, not just the summary
|
|
171
305
|
--force Write files even when the audit reports errors
|
|
306
|
+
--skip-audit Skip the safety report
|
|
172
307
|
--config PATH Use a config file at PATH
|
|
173
|
-
|
|
174
|
-
Flags for dev:
|
|
175
308
|
--port N Dashboard port (default: 4700)
|
|
309
|
+
--help Show this help
|
|
310
|
+
|
|
311
|
+
Examples
|
|
312
|
+
npx webmcp-codegen generate # detect spec, generate tools
|
|
313
|
+
npx webmcp-codegen generate --dry-run # preview without writing
|
|
314
|
+
npx webmcp-codegen dev # open the dashboard
|
|
315
|
+
npx webmcp-codegen generate --verbose # see all 72 tools listed
|
|
316
|
+
|
|
317
|
+
Docs
|
|
318
|
+
https://webmcp-codegen.vercel.app/docs
|
|
176
319
|
`;
|
|
177
|
-
var CONFIG_FILE = "codegen.config.mjs";
|
|
178
|
-
var MAX_LISTED_TOOLS = 15;
|
|
179
320
|
async function main() {
|
|
180
|
-
const {
|
|
321
|
+
const { values, positionals } = parseArgs({
|
|
322
|
+
args: process.argv.slice(2),
|
|
181
323
|
allowPositionals: true,
|
|
182
324
|
options: {
|
|
183
325
|
"dry-run": { type: "boolean", default: false },
|
|
184
326
|
"skip-audit": { type: "boolean", default: false },
|
|
185
327
|
force: { type: "boolean", default: false },
|
|
328
|
+
verbose: { type: "boolean", default: false },
|
|
186
329
|
watch: { type: "boolean", default: false },
|
|
187
330
|
config: { type: "string" },
|
|
188
331
|
spec: { type: "string" },
|
|
@@ -191,28 +334,32 @@ async function main() {
|
|
|
191
334
|
help: { type: "boolean", default: false }
|
|
192
335
|
}
|
|
193
336
|
});
|
|
194
|
-
const
|
|
195
|
-
|
|
337
|
+
const flags = {
|
|
338
|
+
dryRun: values["dry-run"] ?? false,
|
|
339
|
+
skipAudit: values["skip-audit"] ?? false,
|
|
340
|
+
force: values.force ?? false,
|
|
341
|
+
verbose: values.verbose ?? false,
|
|
342
|
+
watch: values.watch ?? false,
|
|
343
|
+
config: values.config,
|
|
344
|
+
spec: values.spec,
|
|
345
|
+
out: values.out,
|
|
346
|
+
port: values.port ? Number.parseInt(values.port, 10) : void 0,
|
|
347
|
+
help: values.help
|
|
348
|
+
};
|
|
349
|
+
if (flags.help) {
|
|
196
350
|
console.log(HELP);
|
|
197
351
|
return 0;
|
|
198
352
|
}
|
|
353
|
+
const command = positionals[0] ?? "generate";
|
|
199
354
|
switch (command) {
|
|
200
355
|
case "init":
|
|
201
356
|
return init();
|
|
202
357
|
case "dev":
|
|
203
|
-
return dev(
|
|
358
|
+
return dev(flags.port ?? 4700);
|
|
204
359
|
case "generate":
|
|
205
|
-
return generate(
|
|
206
|
-
dryRun: values["dry-run"],
|
|
207
|
-
skipAudit: values["skip-audit"],
|
|
208
|
-
force: values.force,
|
|
209
|
-
watch: values.watch,
|
|
210
|
-
configPath: values.config,
|
|
211
|
-
spec: values.spec,
|
|
212
|
-
out: values.out
|
|
213
|
-
});
|
|
360
|
+
return generate(flags);
|
|
214
361
|
default:
|
|
215
|
-
console.error(`Unknown command
|
|
362
|
+
console.error(`Unknown command: ${command}
|
|
216
363
|
`);
|
|
217
364
|
console.log(HELP);
|
|
218
365
|
return 1;
|
|
@@ -220,9 +367,12 @@ async function main() {
|
|
|
220
367
|
}
|
|
221
368
|
async function init() {
|
|
222
369
|
const cwd = process.cwd();
|
|
223
|
-
const
|
|
370
|
+
const configFile = CONFIG_FILE_NAMES[0] ?? "codegen.config.mjs";
|
|
371
|
+
const configPath = join2(cwd, configFile);
|
|
224
372
|
if (existsSync(configPath)) {
|
|
225
|
-
console.error(
|
|
373
|
+
console.error(`
|
|
374
|
+
\u2716 ${configFile} already exists. Nothing to do.
|
|
375
|
+
`);
|
|
226
376
|
return 1;
|
|
227
377
|
}
|
|
228
378
|
const specs = await findSpecs(cwd);
|
|
@@ -245,40 +395,48 @@ export default defineConfig({
|
|
|
245
395
|
});
|
|
246
396
|
`
|
|
247
397
|
);
|
|
248
|
-
console.log(
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
} else {
|
|
254
|
-
console.log(`No OpenAPI spec found, so ${CONFIG_FILE} points at ./openapi.yaml.`);
|
|
255
|
-
console.log("Edit the `spec` path to point at your spec, then run:");
|
|
256
|
-
console.log("\n npx webmcp-codegen generate --dry-run");
|
|
257
|
-
}
|
|
398
|
+
console.log(`
|
|
399
|
+
\u2714 Wrote ${configFile}
|
|
400
|
+
`);
|
|
401
|
+
console.log("Edit it to add sources, change the output directory, or set safety options.");
|
|
402
|
+
console.log("Docs: https://webmcp-codegen.vercel.app/docs/configuration\n");
|
|
258
403
|
return 0;
|
|
259
404
|
}
|
|
260
|
-
async function
|
|
405
|
+
async function dev(port) {
|
|
261
406
|
const cwd = process.cwd();
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
407
|
+
const server = await startDevServer({ cwd, port, open: true });
|
|
408
|
+
console.log(`
|
|
409
|
+
\u2714 Dashboard: http://localhost:${port}
|
|
410
|
+
`);
|
|
411
|
+
console.log("List, describe, enable, and test your tools. Ctrl+C to stop.\n");
|
|
412
|
+
await new Promise((resolveExit) => {
|
|
413
|
+
process.on("SIGINT", () => {
|
|
414
|
+
server.close();
|
|
415
|
+
resolveExit();
|
|
416
|
+
});
|
|
417
|
+
});
|
|
418
|
+
return 0;
|
|
268
419
|
}
|
|
269
|
-
async function
|
|
270
|
-
const
|
|
271
|
-
const
|
|
420
|
+
async function generate(flags) {
|
|
421
|
+
const cwd = process.cwd();
|
|
422
|
+
const setup = await resolveSetup(cwd, {
|
|
423
|
+
dryRun: flags.dryRun,
|
|
424
|
+
skipAudit: flags.skipAudit,
|
|
425
|
+
force: flags.force,
|
|
426
|
+
watch: flags.watch,
|
|
427
|
+
spec: flags.spec,
|
|
428
|
+
out: flags.out,
|
|
429
|
+
configPath: flags.config
|
|
430
|
+
});
|
|
272
431
|
const result = await runGenerate(setup.config, {
|
|
273
432
|
cwd,
|
|
274
433
|
dryRun: flags.dryRun,
|
|
275
|
-
skipAudit: flags.skipAudit,
|
|
276
434
|
force: flags.force,
|
|
277
|
-
|
|
435
|
+
skipAudit: flags.skipAudit
|
|
278
436
|
});
|
|
279
437
|
let wiring = null;
|
|
280
438
|
if (!result.blocked && setup.app) {
|
|
281
|
-
const outDir =
|
|
439
|
+
const outDir = setup.config.generate[0]?.outDir;
|
|
282
440
|
if (outDir) {
|
|
283
441
|
wiring = await planWiring(cwd, setup.app, outDir);
|
|
284
442
|
if (wiring && wiring.edits.length > 0 && !flags.dryRun && result.wrote) {
|
|
@@ -289,143 +447,22 @@ async function runOnce(cwd, flags) {
|
|
|
289
447
|
if (!setup.fromConfigFile && !flags.dryRun && result.wrote) {
|
|
290
448
|
await saveDataFile(cwd, setup.remember);
|
|
291
449
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return config.generate[0]?.outDir;
|
|
297
|
-
}
|
|
298
|
-
function printReport(result, flags, setup, wiring, cwd) {
|
|
299
|
-
const { tools, skipped, findings, files, notes, blocked } = result;
|
|
300
|
-
console.log(`
|
|
301
|
-
webmcp-codegen (${setup.label}): ${tools.length} tool(s)`);
|
|
302
|
-
for (const note of notes) {
|
|
303
|
-
console.log(`
|
|
304
|
-
note: ${note}`);
|
|
305
|
-
}
|
|
306
|
-
if (skipped.length > 0) {
|
|
307
|
-
console.log(`
|
|
308
|
-
${skipped.length} endpoint(s) skipped:`);
|
|
309
|
-
for (const entry of skipped) {
|
|
310
|
-
console.log(` ${entry.ref}: ${entry.reason}`);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
console.log("");
|
|
314
|
-
const listed = tools.slice(0, MAX_LISTED_TOOLS);
|
|
315
|
-
for (const tool of listed) {
|
|
316
|
-
const state = tool.enabledByDefault ? "" : " starts disabled";
|
|
317
|
-
console.log(` ${tool.name} [${tool.sideEffect}]${state} \u2190 ${tool.source.ref}`);
|
|
318
|
-
}
|
|
319
|
-
if (tools.length > listed.length) {
|
|
320
|
-
console.log(` \u2026and ${tools.length - listed.length} more`);
|
|
321
|
-
}
|
|
322
|
-
if (findings.length > 0) {
|
|
323
|
-
console.log("");
|
|
324
|
-
for (const finding of findings) {
|
|
325
|
-
const icon = finding.level === "error" ? "\u2716" : "\u26A0";
|
|
326
|
-
const where = finding.tool ? ` (${finding.tool})` : "";
|
|
327
|
-
console.log(` ${icon} ${finding.message}${where}`);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
if (files.length > 0) {
|
|
331
|
-
console.log("");
|
|
332
|
-
for (const file of files) {
|
|
333
|
-
if (file.action === "unchanged" && !file.conflict) continue;
|
|
334
|
-
const shown = file.conflict ? `conflict \u2192 wrote ${relative2(cwd, file.conflict)}` : file.action;
|
|
335
|
-
console.log(` ${shown}: ${relative2(cwd, file.path)}`);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
if (wiring) {
|
|
339
|
-
if (wiring.alreadyWired) {
|
|
340
|
-
console.log("\n registration: already wired into your app");
|
|
341
|
-
} else if (wiring.edits.length > 0) {
|
|
342
|
-
console.log(flags.dryRun ? "\n registration (would do):" : "\n registration:");
|
|
343
|
-
for (const edit of wiring.edits) {
|
|
344
|
-
console.log(` ${edit.summary}`);
|
|
345
|
-
}
|
|
346
|
-
if (!flags.dryRun) {
|
|
347
|
-
console.log(" undo: delete the added lines (nothing else was touched)");
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
} else if (!blocked && setup.app) {
|
|
351
|
-
console.log("\n registration: could not find your app's entry file, so add this by hand:");
|
|
352
|
-
console.log(' import { registerAllTools } from "<path-to>/src/webmcp";');
|
|
353
|
-
console.log(" void registerAllTools();");
|
|
354
|
-
}
|
|
355
|
-
if (blocked) {
|
|
356
|
-
console.log(
|
|
357
|
-
"\nGeneration blocked by audit errors. Fix them, or re-run with --force to write anyway."
|
|
358
|
-
);
|
|
359
|
-
return;
|
|
450
|
+
if (flags.verbose) {
|
|
451
|
+
renderVerbose(result, setup, cwd);
|
|
452
|
+
} else {
|
|
453
|
+
renderSummary(result, setup, cwd, wiring);
|
|
360
454
|
}
|
|
361
|
-
if (flags.dryRun) {
|
|
362
|
-
console.log("\
|
|
363
|
-
return;
|
|
455
|
+
if (flags.watch && !flags.dryRun) {
|
|
456
|
+
console.log(dim("\n --watch is not implemented yet. Run generate again after changes.\n"));
|
|
364
457
|
}
|
|
365
|
-
|
|
458
|
+
return result.blocked ? 1 : 0;
|
|
366
459
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
parts.push(`${disabled.length} tool(s) start disabled (open the file and uncomment to enable)`);
|
|
460
|
+
main().then(
|
|
461
|
+
(code) => process.exit(code),
|
|
462
|
+
(error) => {
|
|
463
|
+
console.error("\n\u2716 Unexpected error:", error instanceof Error ? error.message : error);
|
|
464
|
+
console.error("\nPlease report this: https://github.com/SouravInsights/groundstate/issues\n");
|
|
465
|
+
process.exit(1);
|
|
374
466
|
}
|
|
375
|
-
|
|
376
|
-
Done. ${parts.join("; ")}.`);
|
|
377
|
-
const suggestion = pickSuggestedTool(result.tools);
|
|
378
|
-
console.log("\nTry it:");
|
|
379
|
-
console.log(" 1. Start your app and open it in Chrome.");
|
|
380
|
-
console.log(" 2. Turn on chrome://flags/#enable-webmcp-testing and reload the page.");
|
|
381
|
-
if (suggestion) {
|
|
382
|
-
console.log(` 3. Ask the agent: "${suggestion}"`);
|
|
383
|
-
} else {
|
|
384
|
-
console.log(" 3. Ask the agent to use one of your tools.");
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
function pickSuggestedTool(tools) {
|
|
388
|
-
const reads = tools.filter((tool2) => tool2.enabledByDefault && tool2.endpointRole === "endpoint");
|
|
389
|
-
if (reads.length === 0) return void 0;
|
|
390
|
-
const tool = reads.find((candidate) => /^(list|get|search|find|fetch|recent)-/.test(candidate.name)) ?? reads[0];
|
|
391
|
-
if (!tool) return void 0;
|
|
392
|
-
const description = tool.description.trim().replace(/\.$/, "");
|
|
393
|
-
const looksTemplated = /^(GET|POST|PUT|PATCH|DELETE)\s/.test(description);
|
|
394
|
-
const phrase = looksTemplated ? tool.name.replace(/-/g, " ") : description.charAt(0).toLowerCase() + description.slice(1);
|
|
395
|
-
return phrase;
|
|
396
|
-
}
|
|
397
|
-
async function dev(port) {
|
|
398
|
-
const { startDevServer } = await import("./server-DWP6IHCS.js");
|
|
399
|
-
const server = await startDevServer({ cwd: process.cwd(), port });
|
|
400
|
-
console.log(`
|
|
401
|
-
webmcp-codegen dashboard: http://localhost:${port}`);
|
|
402
|
-
console.log("List, describe, enable, and try your tools. Ctrl+C to stop.\n");
|
|
403
|
-
await new Promise((resolveExit) => {
|
|
404
|
-
process.on("SIGINT", () => {
|
|
405
|
-
server.close();
|
|
406
|
-
resolveExit();
|
|
407
|
-
});
|
|
408
|
-
});
|
|
409
|
-
return 0;
|
|
410
|
-
}
|
|
411
|
-
async function watchLoop(cwd, flags) {
|
|
412
|
-
await runOnce(cwd, { ...flags, dryRun: false });
|
|
413
|
-
console.log("\nWatching for changes\u2026 (Ctrl+C to stop)");
|
|
414
|
-
let timer;
|
|
415
|
-
watch(cwd, { recursive: true }, (_event, filename) => {
|
|
416
|
-
if (!filename) return;
|
|
417
|
-
if (/node_modules|\.git|\/dist|\/src\/webmcp|\.webmcp-codegen\.json/.test(filename)) return;
|
|
418
|
-
if (!/\.(ya?ml|json|ts|tsx|mts|mjs)$/.test(filename)) return;
|
|
419
|
-
clearTimeout(timer);
|
|
420
|
-
timer = setTimeout(() => {
|
|
421
|
-
runOnce(cwd, { ...flags, dryRun: false }).catch((error) => {
|
|
422
|
-
console.error(error instanceof Error ? error.message : error);
|
|
423
|
-
});
|
|
424
|
-
}, 300);
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
main().then((code) => process.exit(code)).catch((error) => {
|
|
428
|
-
console.error(error instanceof Error ? error.message : error);
|
|
429
|
-
process.exit(1);
|
|
430
|
-
});
|
|
467
|
+
);
|
|
431
468
|
//# sourceMappingURL=cli.js.map
|