@opentiny/webmcp-cli 0.0.1-alpha.5 → 0.0.1-alpha.6
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/bin.cjs +215 -89
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +198 -72
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +10 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/webmcp-tools/juejin.cn.js +54 -21
- package/package.json +1 -1
package/dist/bin.cjs
CHANGED
|
@@ -26,25 +26,197 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// src/bin.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
var import_picocolors2 = __toESM(require("picocolors"), 1);
|
|
29
|
-
var
|
|
30
|
-
var
|
|
29
|
+
var import_fs3 = require("fs");
|
|
30
|
+
var import_path3 = require("path");
|
|
31
|
+
|
|
32
|
+
// src/expand-file-refs.ts
|
|
33
|
+
var import_fs = require("fs");
|
|
34
|
+
var import_path = require("path");
|
|
35
|
+
var import_url = require("url");
|
|
36
|
+
var JSON_STRING_LITERAL = /"(?:[^"\\]|\\.)*"/g;
|
|
37
|
+
var UNQUOTED_FILE_REF = /(?<![\\"])@(base64)?file:([^\s"',}\]]+)/g;
|
|
38
|
+
var FILE_REF_PREFIX = /^@(base64)?file:(.+)$/s;
|
|
39
|
+
function resolveFilePath(filePath, baseDir = process.cwd()) {
|
|
40
|
+
let normalizedPath = filePath.trim();
|
|
41
|
+
if (normalizedPath.startsWith('"') && normalizedPath.endsWith('"') || normalizedPath.startsWith("'") && normalizedPath.endsWith("'")) {
|
|
42
|
+
normalizedPath = normalizedPath.slice(1, -1).trim();
|
|
43
|
+
}
|
|
44
|
+
if (normalizedPath.startsWith("file://")) {
|
|
45
|
+
normalizedPath = (0, import_url.fileURLToPath)(normalizedPath);
|
|
46
|
+
}
|
|
47
|
+
if ((0, import_path.isAbsolute)(normalizedPath)) {
|
|
48
|
+
return (0, import_path.normalize)(normalizedPath);
|
|
49
|
+
}
|
|
50
|
+
return (0, import_path.resolve)(baseDir, normalizedPath);
|
|
51
|
+
}
|
|
52
|
+
function decodeFilePath(rawPath) {
|
|
53
|
+
return rawPath.replace(/\\\\/g, "\\");
|
|
54
|
+
}
|
|
55
|
+
function readFileRefContent(filePath, baseDir, base64) {
|
|
56
|
+
const absPath = resolveFilePath(filePath, baseDir);
|
|
57
|
+
let content;
|
|
58
|
+
try {
|
|
59
|
+
content = (0, import_fs.readFileSync)(absPath, "utf-8");
|
|
60
|
+
} catch (e) {
|
|
61
|
+
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6\u5F15\u7528 "${filePath}" (${absPath}): ${e.message}`);
|
|
62
|
+
}
|
|
63
|
+
return base64 ? Buffer.from(content, "utf-8").toString("base64") : content;
|
|
64
|
+
}
|
|
65
|
+
function expandFileRefValue(rawInner, baseDir) {
|
|
66
|
+
const match = rawInner.match(FILE_REF_PREFIX);
|
|
67
|
+
if (!match) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const [, base64Flag, rawPath] = match;
|
|
71
|
+
const filePath = decodeFilePath(rawPath);
|
|
72
|
+
const value = readFileRefContent(filePath, baseDir, Boolean(base64Flag));
|
|
73
|
+
return JSON.stringify(value);
|
|
74
|
+
}
|
|
75
|
+
function expandQuotedFileRefs(argsJson, baseDir) {
|
|
76
|
+
return argsJson.replace(JSON_STRING_LITERAL, (jsonStringLiteral) => {
|
|
77
|
+
const rawInner = jsonStringLiteral.slice(1, -1);
|
|
78
|
+
const replacement = expandFileRefValue(rawInner, baseDir);
|
|
79
|
+
return replacement ?? jsonStringLiteral;
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
function expandUnquotedFileRefs(argsJson, baseDir) {
|
|
83
|
+
return argsJson.replace(UNQUOTED_FILE_REF, (match, base64Flag, filePath) => {
|
|
84
|
+
const value = readFileRefContent(filePath, baseDir, Boolean(base64Flag));
|
|
85
|
+
return JSON.stringify(value);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
function expandFileRefs(argsJson, baseDir = process.cwd()) {
|
|
89
|
+
const withQuotedExpanded = expandQuotedFileRefs(argsJson, baseDir);
|
|
90
|
+
return expandUnquotedFileRefs(withQuotedExpanded, baseDir);
|
|
91
|
+
}
|
|
92
|
+
function getFileBaseDir(fileOption) {
|
|
93
|
+
if (!fileOption) {
|
|
94
|
+
return process.cwd();
|
|
95
|
+
}
|
|
96
|
+
return (0, import_path.dirname)((0, import_path.resolve)(process.cwd(), fileOption));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/parse-run-args.ts
|
|
100
|
+
var import_json5 = __toESM(require("json5"), 1);
|
|
101
|
+
function cleanJsonString(str) {
|
|
102
|
+
let cleaned = str.trim();
|
|
103
|
+
if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
104
|
+
cleaned = cleaned.slice(1, -1).trim();
|
|
105
|
+
}
|
|
106
|
+
return cleaned;
|
|
107
|
+
}
|
|
108
|
+
function looksLikeObjectBody(raw) {
|
|
109
|
+
return /^("?[\w-]+"?\s*:)/.test(raw);
|
|
110
|
+
}
|
|
111
|
+
function joinShellArgs(args) {
|
|
112
|
+
const cleaned = args.map(cleanJsonString);
|
|
113
|
+
const first = cleaned[0] ?? "";
|
|
114
|
+
if (first.startsWith("{")) {
|
|
115
|
+
return cleaned.join(" ");
|
|
116
|
+
}
|
|
117
|
+
if (looksLikeObjectBody(first)) {
|
|
118
|
+
let joined = cleaned.join(" ");
|
|
119
|
+
if (!joined.startsWith("{")) {
|
|
120
|
+
joined = `{${joined}}`;
|
|
121
|
+
}
|
|
122
|
+
if (!joined.endsWith("}")) {
|
|
123
|
+
joined = `${joined}}`;
|
|
124
|
+
}
|
|
125
|
+
return joined;
|
|
126
|
+
}
|
|
127
|
+
return cleaned.join(" ");
|
|
128
|
+
}
|
|
129
|
+
function insertMissingCommas(raw) {
|
|
130
|
+
return raw.replace(/"(\s+)("?[\w-]+"?\s*:)/g, '",$2');
|
|
131
|
+
}
|
|
132
|
+
function quoteUnquotedStringValues(raw) {
|
|
133
|
+
return raw.replace(
|
|
134
|
+
/([{,]\s*(?:"([^"]+)"|([\w-]+))\s*:\s*)(?!"@(?:base64)?file:|"|true|false|null|-?\d|\{|\[)([^",}\]]+?)(?=\s*[,}])/g,
|
|
135
|
+
(_match, prefix, _quotedKey, _unquotedKey, value) => {
|
|
136
|
+
const trimmed = value.trim();
|
|
137
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(trimmed)) {
|
|
138
|
+
return prefix + trimmed;
|
|
139
|
+
}
|
|
140
|
+
return prefix + JSON.stringify(trimmed);
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
function normalizeShellDamagedJson(raw) {
|
|
145
|
+
let normalized = raw.trim();
|
|
146
|
+
normalized = insertMissingCommas(normalized);
|
|
147
|
+
normalized = quoteUnquotedStringValues(normalized);
|
|
148
|
+
return normalized;
|
|
149
|
+
}
|
|
150
|
+
function buildArgsFromKeyValuePairs(args) {
|
|
151
|
+
const obj = {};
|
|
152
|
+
for (const pair of args) {
|
|
153
|
+
const index = pair.indexOf("=");
|
|
154
|
+
if (index === -1) {
|
|
155
|
+
throw new Error(`\u65E0\u6548\u7684\u53C2\u6570\u683C\u5F0F "${pair}"\u3002\u8BF7\u4F7F\u7528 key=value\uFF0C\u6216 JSON / -f \u6587\u4EF6\u3002`);
|
|
156
|
+
}
|
|
157
|
+
const key = pair.substring(0, index).trim();
|
|
158
|
+
let val = cleanJsonString(pair.substring(index + 1).trim());
|
|
159
|
+
try {
|
|
160
|
+
obj[key] = JSON.parse(val);
|
|
161
|
+
} catch {
|
|
162
|
+
obj[key] = val;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return JSON.stringify(obj);
|
|
166
|
+
}
|
|
167
|
+
function parseArgsJson(raw) {
|
|
168
|
+
const trimmed = cleanJsonString(raw);
|
|
169
|
+
try {
|
|
170
|
+
return JSON.stringify(import_json5.default.parse(trimmed));
|
|
171
|
+
} catch (firstError) {
|
|
172
|
+
const repaired = normalizeShellDamagedJson(trimmed);
|
|
173
|
+
try {
|
|
174
|
+
return JSON.stringify(import_json5.default.parse(repaired));
|
|
175
|
+
} catch {
|
|
176
|
+
const hint = `\u63D0\u793A\uFF1Abash \u4E2D JSON \u5FC5\u987B\u7528\u5355\u5F15\u53F7\u5305\u88F9\uFF0C\u4F8B\u5982 '{"title":"\u6807\u9898","content":"@base64file:./article.md"}'\uFF1B\u6216\u4F7F\u7528 key=value\uFF1Atitle=\u6807\u9898 content=@base64file:./article.md\uFF1B\u6216\u4F7F\u7528 -f args.json\u3002`;
|
|
177
|
+
const message = firstError instanceof Error ? firstError.message : String(firstError);
|
|
178
|
+
throw new Error(`\u53C2\u6570\u4E0D\u662F\u6709\u6548\u7684 JSON \u6216 JS \u5BF9\u8C61: ${message}
|
|
179
|
+
${hint}`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
function prepareRunArgsJson(args, fileContent, baseDir) {
|
|
184
|
+
let raw = "";
|
|
185
|
+
if (fileContent !== void 0) {
|
|
186
|
+
raw = fileContent.trim();
|
|
187
|
+
} else if (args.length > 0) {
|
|
188
|
+
const joined = joinShellArgs(args);
|
|
189
|
+
if (joined.startsWith("{") || looksLikeObjectBody(joined)) {
|
|
190
|
+
raw = joined;
|
|
191
|
+
} else if (args.every((arg) => arg.includes("="))) {
|
|
192
|
+
raw = buildArgsFromKeyValuePairs(args);
|
|
193
|
+
} else {
|
|
194
|
+
raw = joined;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (!raw) {
|
|
198
|
+
throw new Error("\u5FC5\u987B\u63D0\u4F9B\u53C2\u6570\u6216\u901A\u8FC7 -f/--file \u6307\u5B9A\u53C2\u6570\u6587\u4EF6");
|
|
199
|
+
}
|
|
200
|
+
const expanded = expandFileRefs(raw, baseDir);
|
|
201
|
+
return parseArgsJson(expanded);
|
|
202
|
+
}
|
|
31
203
|
|
|
32
204
|
// src/browser.ts
|
|
33
205
|
var import_puppeteer_core = __toESM(require("puppeteer-core"), 1);
|
|
34
206
|
var import_picocolors = __toESM(require("picocolors"), 1);
|
|
35
|
-
var
|
|
207
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
36
208
|
var import_os = __toESM(require("os"), 1);
|
|
37
|
-
var
|
|
209
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
38
210
|
var import_http = __toESM(require("http"), 1);
|
|
39
211
|
var import_child_process = require("child_process");
|
|
40
|
-
var
|
|
212
|
+
var import_url2 = require("url");
|
|
41
213
|
var import_meta = {};
|
|
42
|
-
var __filename = (0,
|
|
43
|
-
var __dirname =
|
|
214
|
+
var __filename = (0, import_url2.fileURLToPath)(import_meta.url);
|
|
215
|
+
var __dirname = import_path2.default.dirname(__filename);
|
|
44
216
|
var CDP_PORT = 9222;
|
|
45
217
|
var CDP_URL = `http://localhost:${CDP_PORT}`;
|
|
46
218
|
function httpGet(url, timeoutMs = 1500) {
|
|
47
|
-
return new Promise((
|
|
219
|
+
return new Promise((resolve3, reject) => {
|
|
48
220
|
const req = import_http.default.get(url, { timeout: timeoutMs }, (res) => {
|
|
49
221
|
let data = "";
|
|
50
222
|
res.on("data", (chunk) => {
|
|
@@ -52,7 +224,7 @@ function httpGet(url, timeoutMs = 1500) {
|
|
|
52
224
|
});
|
|
53
225
|
res.on("end", () => {
|
|
54
226
|
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
55
|
-
|
|
227
|
+
resolve3(data);
|
|
56
228
|
} else {
|
|
57
229
|
reject(new Error(`HTTP ${res.statusCode}`));
|
|
58
230
|
}
|
|
@@ -93,9 +265,9 @@ function getDefaultBrowserPath() {
|
|
|
93
265
|
const platform = import_os.default.platform();
|
|
94
266
|
if (platform === "darwin") {
|
|
95
267
|
const chromePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
|
|
96
|
-
if (
|
|
268
|
+
if (import_fs2.default.existsSync(chromePath)) return { path: chromePath, name: "Chrome" };
|
|
97
269
|
const edgePath = "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge";
|
|
98
|
-
if (
|
|
270
|
+
if (import_fs2.default.existsSync(edgePath)) return { path: edgePath, name: "Edge" };
|
|
99
271
|
return null;
|
|
100
272
|
} else if (platform === "win32") {
|
|
101
273
|
const chromePaths = [
|
|
@@ -103,7 +275,7 @@ function getDefaultBrowserPath() {
|
|
|
103
275
|
process.env.PROGRAMFILES + "\\Google\\Chrome\\Application\\chrome.exe",
|
|
104
276
|
process.env["PROGRAMFILES(X86)"] + "\\Google\\Chrome\\Application\\chrome.exe"
|
|
105
277
|
];
|
|
106
|
-
const foundChrome = chromePaths.find((p) =>
|
|
278
|
+
const foundChrome = chromePaths.find((p) => import_fs2.default.existsSync(p));
|
|
107
279
|
if (foundChrome) return { path: foundChrome, name: "Chrome" };
|
|
108
280
|
const edgePaths = [
|
|
109
281
|
process.env.LOCALAPPDATA + "\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
@@ -112,7 +284,7 @@ function getDefaultBrowserPath() {
|
|
|
112
284
|
"C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe",
|
|
113
285
|
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
|
|
114
286
|
];
|
|
115
|
-
const foundEdge = edgePaths.find((p) =>
|
|
287
|
+
const foundEdge = edgePaths.find((p) => import_fs2.default.existsSync(p));
|
|
116
288
|
if (foundEdge) return { path: foundEdge, name: "Edge" };
|
|
117
289
|
return null;
|
|
118
290
|
} else {
|
|
@@ -124,17 +296,17 @@ function getDefaultBrowserPath() {
|
|
|
124
296
|
{ p: "/usr/bin/microsoft-edge", name: "Edge" },
|
|
125
297
|
{ p: "/usr/bin/microsoft-edge-stable", name: "Edge" }
|
|
126
298
|
];
|
|
127
|
-
const found = paths.find(({ p }) =>
|
|
299
|
+
const found = paths.find(({ p }) => import_fs2.default.existsSync(p));
|
|
128
300
|
return found ? { path: found.p, name: found.name } : null;
|
|
129
301
|
}
|
|
130
302
|
}
|
|
131
303
|
async function startBrowserInBackground() {
|
|
132
304
|
const browserInfo = getDefaultBrowserPath();
|
|
133
|
-
if (!browserInfo || !
|
|
305
|
+
if (!browserInfo || !import_fs2.default.existsSync(browserInfo.path)) {
|
|
134
306
|
throw new Error("\u65E0\u6CD5\u5728\u7CFB\u7EDF\u4E2D\u627E\u5230 Chrome \u6216 Edge \u6D4F\u89C8\u5668\u7684\u9ED8\u8BA4\u5B89\u88C5\u8DEF\u5F84\u3002");
|
|
135
307
|
}
|
|
136
308
|
console.log(import_picocolors.default.yellow(`\u6B63\u5728\u542F\u52A8\u540E\u53F0 ${browserInfo.name} \u5B9E\u4F8B (\u7AEF\u53E3: ${CDP_PORT})...`));
|
|
137
|
-
const userDataDir = process.env.WEBMCP_WORKSPACE ||
|
|
309
|
+
const userDataDir = process.env.WEBMCP_WORKSPACE || import_path2.default.join(import_os.default.homedir(), ".webmcp_chrome_profile");
|
|
138
310
|
const child = (0, import_child_process.spawn)(
|
|
139
311
|
browserInfo.path,
|
|
140
312
|
[
|
|
@@ -162,7 +334,7 @@ async function startBrowserInBackground() {
|
|
|
162
334
|
}
|
|
163
335
|
} catch (e) {
|
|
164
336
|
}
|
|
165
|
-
await new Promise((
|
|
337
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
166
338
|
}
|
|
167
339
|
throw new Error(`${browserInfo.name} \u542F\u52A8\u8D85\u65F6\uFF0C\u65E0\u6CD5\u8FDE\u63A5\u5230 CDP \u7AEF\u53E3\u3002`);
|
|
168
340
|
}
|
|
@@ -345,18 +517,18 @@ async function injectWebMCPPolyfillAndTools(page2, force = false) {
|
|
|
345
517
|
}).catch(() => false);
|
|
346
518
|
if (!polyfillReady) {
|
|
347
519
|
console.log(import_picocolors.default.cyan("\u5F53\u524D\u9875\u9762\u5C1A\u672A\u6CE8\u5165 WebMCP \u73AF\u5883\uFF0C\u6B63\u5728\u6267\u884C\u81EA\u52A8\u6CE8\u5165..."));
|
|
348
|
-
const injectScriptPath =
|
|
349
|
-
if (!
|
|
520
|
+
const injectScriptPath = import_path2.default.resolve(__dirname, "inject-bundle.js");
|
|
521
|
+
if (!import_fs2.default.existsSync(injectScriptPath)) {
|
|
350
522
|
throw new Error(`Cannot find inject-bundle.js at ${injectScriptPath}. Please ensure you run 'pnpm build:inject' first.`);
|
|
351
523
|
}
|
|
352
|
-
const scriptContent =
|
|
524
|
+
const scriptContent = import_fs2.default.readFileSync(injectScriptPath, "utf-8");
|
|
353
525
|
try {
|
|
354
526
|
await page2.evaluate(scriptContent);
|
|
355
527
|
} catch (err) {
|
|
356
528
|
const msg = err instanceof Error ? err.message : String(err);
|
|
357
529
|
throw new Error("\u81EA\u52A8\u6CE8\u5165\u811A\u672C\u6267\u884C\u5931\u8D25: " + msg);
|
|
358
530
|
}
|
|
359
|
-
await new Promise((
|
|
531
|
+
await new Promise((resolve3) => setTimeout(resolve3, 300));
|
|
360
532
|
}
|
|
361
533
|
await injectDomainTools(page2);
|
|
362
534
|
}
|
|
@@ -368,12 +540,12 @@ async function injectDomainTools(page2) {
|
|
|
368
540
|
} catch {
|
|
369
541
|
return;
|
|
370
542
|
}
|
|
371
|
-
const toolBundlePath =
|
|
372
|
-
if (!
|
|
543
|
+
const toolBundlePath = import_path2.default.resolve(__dirname, "webmcp-tools", `${hostname}.js`);
|
|
544
|
+
if (!import_fs2.default.existsSync(toolBundlePath)) {
|
|
373
545
|
return;
|
|
374
546
|
}
|
|
375
547
|
console.log(import_picocolors.default.cyan(`\u68C0\u6D4B\u5230\u57DF\u540D ${hostname} \u6709\u9884\u7F6E\u5DE5\u5177\uFF0C\u6B63\u5728\u6CE8\u5165...`));
|
|
376
|
-
const toolScript =
|
|
548
|
+
const toolScript = import_fs2.default.readFileSync(toolBundlePath, "utf-8");
|
|
377
549
|
try {
|
|
378
550
|
await page2.evaluate(toolScript);
|
|
379
551
|
console.log(import_picocolors.default.green(`\u5DF2\u4E3A ${hostname} \u6CE8\u5165\u9884\u7F6E\u5DE5\u5177`));
|
|
@@ -444,7 +616,7 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
444
616
|
if (pUrl.startsWith("devtools://")) return null;
|
|
445
617
|
const pTitle = await Promise.race([
|
|
446
618
|
p.title().catch(() => "Unknown"),
|
|
447
|
-
new Promise((
|
|
619
|
+
new Promise((resolve3) => setTimeout(() => resolve3("Unknown"), 500))
|
|
448
620
|
]);
|
|
449
621
|
return {
|
|
450
622
|
// 使用真实的 Chrome target ID,而非数组下标
|
|
@@ -464,7 +636,6 @@ async function stateCommand({ tabid: tabid2 }) {
|
|
|
464
636
|
}
|
|
465
637
|
|
|
466
638
|
// src/commands/run.ts
|
|
467
|
-
var import_json5 = __toESM(require("json5"), 1);
|
|
468
639
|
async function runCommand({
|
|
469
640
|
toolName,
|
|
470
641
|
argsJson,
|
|
@@ -473,16 +644,7 @@ async function runCommand({
|
|
|
473
644
|
const browser2 = await connectBrowser();
|
|
474
645
|
try {
|
|
475
646
|
const page2 = await getTargetPage(browser2, tabid2);
|
|
476
|
-
|
|
477
|
-
if (cleanedArgs.startsWith("'") && cleanedArgs.endsWith("'")) {
|
|
478
|
-
cleanedArgs = cleanedArgs.slice(1, -1).trim();
|
|
479
|
-
}
|
|
480
|
-
try {
|
|
481
|
-
const obj = import_json5.default.parse(cleanedArgs);
|
|
482
|
-
cleanedArgs = JSON.stringify(obj);
|
|
483
|
-
} catch (e) {
|
|
484
|
-
throw new Error(`\u53C2\u6570\u4E0D\u662F\u6709\u6548\u7684 JSON \u6216 JS \u5BF9\u8C61: ${e.message}`);
|
|
485
|
-
}
|
|
647
|
+
const cleanedArgs = argsJson.trim();
|
|
486
648
|
const result2 = await page2.evaluate(async (name, inputString) => {
|
|
487
649
|
const mcp = navigator.modelContextTesting || navigator.modelContext;
|
|
488
650
|
if (!mcp || typeof mcp.executeTool !== "function") {
|
|
@@ -492,9 +654,17 @@ async function runCommand({
|
|
|
492
654
|
if (typeof res === "string") {
|
|
493
655
|
try {
|
|
494
656
|
res = JSON.parse(res);
|
|
495
|
-
} catch
|
|
657
|
+
} catch {
|
|
496
658
|
}
|
|
497
659
|
}
|
|
660
|
+
if (res === void 0 || res === null) {
|
|
661
|
+
throw new Error("\u5DE5\u5177 execute \u672A\u8FD4\u56DE\u7ED3\u679C\uFF0C\u8BF7\u68C0\u67E5\u5DE5\u5177\u5B9E\u73B0\u662F\u5426\u7F3A\u5C11 return");
|
|
662
|
+
}
|
|
663
|
+
if (typeof res === "object" && res.success === false) {
|
|
664
|
+
const failed = res;
|
|
665
|
+
throw new Error(failed.error || failed.message || "\u5DE5\u5177\u6267\u884C\u5931\u8D25");
|
|
666
|
+
}
|
|
667
|
+
return res;
|
|
498
668
|
}, toolName, cleanedArgs);
|
|
499
669
|
return result2;
|
|
500
670
|
} finally {
|
|
@@ -555,7 +725,7 @@ async function tabsOpenCommand(url) {
|
|
|
555
725
|
url = normalizeUrl(url);
|
|
556
726
|
await page2.goto(url, { waitUntil: "domcontentloaded" });
|
|
557
727
|
await injectIntoPage(page2);
|
|
558
|
-
await new Promise((
|
|
728
|
+
await new Promise((resolve3) => setTimeout(resolve3, 500));
|
|
559
729
|
return {
|
|
560
730
|
success: true,
|
|
561
731
|
tabid: await getPageTargetId(page2),
|
|
@@ -656,7 +826,7 @@ async function tabsForwardCommand(tabid2) {
|
|
|
656
826
|
// package.json
|
|
657
827
|
var package_default = {
|
|
658
828
|
name: "@opentiny/webmcp-cli",
|
|
659
|
-
version: "0.0.1-alpha.
|
|
829
|
+
version: "0.0.1-alpha.6",
|
|
660
830
|
type: "module",
|
|
661
831
|
description: "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
|
|
662
832
|
main: "dist/index.js",
|
|
@@ -710,13 +880,6 @@ var package_default = {
|
|
|
710
880
|
|
|
711
881
|
// src/bin.ts
|
|
712
882
|
var program = new import_commander.Command();
|
|
713
|
-
function cleanJsonString(str) {
|
|
714
|
-
let cleaned = str.trim();
|
|
715
|
-
if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
716
|
-
cleaned = cleaned.slice(1, -1).trim();
|
|
717
|
-
}
|
|
718
|
-
return cleaned;
|
|
719
|
-
}
|
|
720
883
|
function parseTabId(id) {
|
|
721
884
|
if (!id) return void 0;
|
|
722
885
|
return id;
|
|
@@ -726,19 +889,6 @@ function handleCommandError(error, commandName) {
|
|
|
726
889
|
console.error(import_picocolors2.default.red(`Error executing ${commandName} command: ${msg}`));
|
|
727
890
|
process.exit(1);
|
|
728
891
|
}
|
|
729
|
-
function expandFileRefs(argsJson) {
|
|
730
|
-
return argsJson.replace(/"@(base64)?file:([^"]+)"/g, (_match, base64Flag, filePath) => {
|
|
731
|
-
const absPath = (0, import_path2.resolve)(process.cwd(), filePath);
|
|
732
|
-
let content;
|
|
733
|
-
try {
|
|
734
|
-
content = (0, import_fs2.readFileSync)(absPath, "utf-8");
|
|
735
|
-
} catch (e) {
|
|
736
|
-
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6\u5F15\u7528 "${filePath}": ${e.message}`);
|
|
737
|
-
}
|
|
738
|
-
const value = base64Flag ? Buffer.from(content, "utf-8").toString("base64") : content;
|
|
739
|
-
return JSON.stringify(value);
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
892
|
program.name("webmcp-cli").description("WebMCP CLI for interacting with browser via CDP").version(package_default.version).option("-w, --workspace <path>", "\u6307\u5B9A\u81EA\u5B9A\u4E49\u7684\u6D4F\u89C8\u5668\u5DE5\u4F5C\u7A7A\u95F4\uFF08\u7528\u6237\u914D\u7F6E\u76EE\u5F55\uFF09\u8DEF\u5F84").hook("preAction", (thisCommand) => {
|
|
743
893
|
const opts = thisCommand.opts();
|
|
744
894
|
if (opts.workspace) {
|
|
@@ -762,42 +912,18 @@ program.command("run <toolName> [args...]").description("\u5411\u6307\u5B9A\u987
|
|
|
762
912
|
\u793A\u4F8B\uFF1Awebmcp-cli run mytool '{"content":"@base64file:./doc.md"}'`
|
|
763
913
|
).action(async (toolName, args, options) => {
|
|
764
914
|
try {
|
|
765
|
-
let
|
|
915
|
+
let fileContent;
|
|
916
|
+
let fileBaseDir = process.cwd();
|
|
766
917
|
if (options.file) {
|
|
767
|
-
const filePath = (0,
|
|
918
|
+
const filePath = (0, import_path3.resolve)(process.cwd(), options.file);
|
|
919
|
+
fileBaseDir = getFileBaseDir(options.file);
|
|
768
920
|
try {
|
|
769
|
-
|
|
921
|
+
fileContent = (0, import_fs3.readFileSync)(filePath, "utf-8");
|
|
770
922
|
} catch (e) {
|
|
771
923
|
throw new Error(`\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6 "${filePath}": ${e.message}`);
|
|
772
924
|
}
|
|
773
|
-
} else if (args && args.length > 0) {
|
|
774
|
-
const firstArg = args[0].trim();
|
|
775
|
-
const cleanedFirstArg = cleanJsonString(firstArg);
|
|
776
|
-
if (cleanedFirstArg.startsWith("{") && cleanedFirstArg.endsWith("}")) {
|
|
777
|
-
finalArgsJson = args.map(cleanJsonString).join(" ");
|
|
778
|
-
} else {
|
|
779
|
-
const obj = {};
|
|
780
|
-
for (const pair of args) {
|
|
781
|
-
const index = pair.indexOf("=");
|
|
782
|
-
if (index === -1) {
|
|
783
|
-
throw new Error(`\u65E0\u6548\u7684\u53C2\u6570\u683C\u5F0F "${pair}"\u3002\u5FC5\u987B\u662F JSON \u5B57\u7B26\u4E32\u6216 key=value \u683C\u5F0F\u3002`);
|
|
784
|
-
}
|
|
785
|
-
const key = pair.substring(0, index).trim();
|
|
786
|
-
let val = pair.substring(index + 1).trim();
|
|
787
|
-
val = cleanJsonString(val);
|
|
788
|
-
try {
|
|
789
|
-
obj[key] = JSON.parse(val);
|
|
790
|
-
} catch {
|
|
791
|
-
obj[key] = val;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
finalArgsJson = JSON.stringify(obj);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
if (!finalArgsJson) {
|
|
798
|
-
throw new Error("\u5FC5\u987B\u63D0\u4F9B\u53C2\u6570\u6216\u901A\u8FC7 -f/--file \u6307\u5B9A\u53C2\u6570\u6587\u4EF6");
|
|
799
925
|
}
|
|
800
|
-
finalArgsJson =
|
|
926
|
+
const finalArgsJson = prepareRunArgsJson(args ?? [], fileContent, fileBaseDir);
|
|
801
927
|
const result2 = await runCommand({
|
|
802
928
|
toolName,
|
|
803
929
|
argsJson: finalArgsJson,
|