@flemist/mcp-project-tools 3.0.8 → 3.0.10
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/build/cli.js +18 -17
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -1
- package/build/startMcpServer-Yp1zN-1S.js +4026 -0
- package/package.json +10 -5
- package/build/startMcpServer-BwbVbpru.js +0 -3506
|
@@ -1,3506 +0,0 @@
|
|
|
1
|
-
import A from "express";
|
|
2
|
-
import { McpServer as ot } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
-
import { randomUUID as nt } from "crypto";
|
|
4
|
-
import * as B from "fs";
|
|
5
|
-
import * as T from "path";
|
|
6
|
-
import it from "path";
|
|
7
|
-
import { StreamableHTTPServerTransport as at } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
8
|
-
import { spawn as ct } from "child_process";
|
|
9
|
-
import { z as h } from "zod";
|
|
10
|
-
import K from "tree-kill";
|
|
11
|
-
import { Pool as lt, poolRunWait as z } from "@flemist/time-limits";
|
|
12
|
-
import { priorityCreate as P } from "@flemist/priority-queue";
|
|
13
|
-
import { useAbortController as ut, combineAbortSignals as dt } from "@flemist/async-utils";
|
|
14
|
-
import ft from "node:os";
|
|
15
|
-
import mt from "picomatch";
|
|
16
|
-
import { webkit as ht, firefox as pt, chromium as gt } from "playwright";
|
|
17
|
-
function wt(t) {
|
|
18
|
-
const { authToken: r } = t;
|
|
19
|
-
return function(o, e, n) {
|
|
20
|
-
if ((o.query.token || o.headers.authorization?.replace("Bearer ", "")) !== r) {
|
|
21
|
-
e.status(401).json({ error: "Unauthorized" });
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
n();
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
async function q(t) {
|
|
28
|
-
const { logFilePath: r, message: s, data: o } = t;
|
|
29
|
-
try {
|
|
30
|
-
const e = (/* @__PURE__ */ new Date()).toISOString().replace(/[TZ]/g, " ").trim(), n = typeof o == "string" ? o : JSON.stringify(o, null, 2), a = `[${e}] ${s}
|
|
31
|
-
${n}
|
|
32
|
-
|
|
33
|
-
`;
|
|
34
|
-
await B.promises.mkdir(T.dirname(r), { recursive: !0 }), await B.promises.appendFile(r, a);
|
|
35
|
-
} catch (e) {
|
|
36
|
-
console.error(`Failed to log "${s}":`, e);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const G = /* @__PURE__ */ new Map();
|
|
40
|
-
function yt(t) {
|
|
41
|
-
return t.headers["mcp-session-id"] || t.headers["x-session-id"] || t.query.token;
|
|
42
|
-
}
|
|
43
|
-
async function bt(t, r) {
|
|
44
|
-
const s = t.createMcpServer(), o = new at({
|
|
45
|
-
sessionIdGenerator: () => r || nt(),
|
|
46
|
-
onsessioninitialized: (n) => {
|
|
47
|
-
G.set(n, o);
|
|
48
|
-
},
|
|
49
|
-
enableJsonResponse: !0
|
|
50
|
-
});
|
|
51
|
-
async function e() {
|
|
52
|
-
const n = o.sessionId;
|
|
53
|
-
n && G.delete(n);
|
|
54
|
-
try {
|
|
55
|
-
await s.close();
|
|
56
|
-
} catch (a) {
|
|
57
|
-
console.error("Failed to close session", a);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
o.onclose = e;
|
|
61
|
-
try {
|
|
62
|
-
return await s.connect(o), o;
|
|
63
|
-
} catch (n) {
|
|
64
|
-
throw await e(), n;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
async function St(t, r, s, o) {
|
|
68
|
-
await q({
|
|
69
|
-
logFilePath: s.logFilePath,
|
|
70
|
-
message: "REQUEST",
|
|
71
|
-
data: t.body
|
|
72
|
-
});
|
|
73
|
-
let e = o ? G.get(o) : null;
|
|
74
|
-
e || (e = await bt(s, o)), await e.handleRequest(t, r, t.body);
|
|
75
|
-
}
|
|
76
|
-
async function xt(t, r, s) {
|
|
77
|
-
const o = s ? G.get(s) : null;
|
|
78
|
-
if (!o) {
|
|
79
|
-
r.status(400).json({ error: "No valid session found" });
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
await o.handleRequest(t, r);
|
|
83
|
-
}
|
|
84
|
-
function $t(t) {
|
|
85
|
-
return async function(s, o) {
|
|
86
|
-
try {
|
|
87
|
-
const e = yt(s);
|
|
88
|
-
s.method === "POST" ? await St(s, o, t, e) : s.method === "GET" ? await xt(s, o, e) : o.status(405).json({ error: "Method not allowed" });
|
|
89
|
-
} catch (e) {
|
|
90
|
-
console.error("Unhandled error in streamableHttpHandler", e), o.status(500).json({
|
|
91
|
-
error: "Internal server error: " + (e instanceof Error ? e.message : "Unknown error")
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
const O = /* @__PURE__ */ new Map();
|
|
97
|
-
let It = 0;
|
|
98
|
-
const ie = 10, Mt = 1800 * 1e3, k = 1e4, Tt = 500, vt = 5e3;
|
|
99
|
-
function Ct(t) {
|
|
100
|
-
const { commandLine: r, commandLineRules: s } = t;
|
|
101
|
-
let o = !1;
|
|
102
|
-
for (const e of s)
|
|
103
|
-
if (new RegExp(e.regexp).test(r))
|
|
104
|
-
switch (e.rule) {
|
|
105
|
-
case "allow":
|
|
106
|
-
o = !0;
|
|
107
|
-
break;
|
|
108
|
-
case "deny":
|
|
109
|
-
o = !1;
|
|
110
|
-
break;
|
|
111
|
-
default:
|
|
112
|
-
throw new Error(`Unknown command line rule: ${e.rule}`);
|
|
113
|
-
}
|
|
114
|
-
return o;
|
|
115
|
-
}
|
|
116
|
-
function kt() {
|
|
117
|
-
return ++It;
|
|
118
|
-
}
|
|
119
|
-
let ae = !1;
|
|
120
|
-
function Nt() {
|
|
121
|
-
if (ae)
|
|
122
|
-
return;
|
|
123
|
-
ae = !0;
|
|
124
|
-
const t = () => {
|
|
125
|
-
console.log("Auto-killing all child processes...");
|
|
126
|
-
for (const [r, s] of Array.from(O.entries()))
|
|
127
|
-
if (s.isRunning && s.pid)
|
|
128
|
-
try {
|
|
129
|
-
K(s.pid, "SIGKILL");
|
|
130
|
-
} catch (o) {
|
|
131
|
-
console.error(`Error killing process ${r}:`, o);
|
|
132
|
-
}
|
|
133
|
-
process.exit(0);
|
|
134
|
-
};
|
|
135
|
-
process.on("SIGINT", t), process.on("SIGTERM", t);
|
|
136
|
-
}
|
|
137
|
-
function Q() {
|
|
138
|
-
const t = Date.now(), r = [];
|
|
139
|
-
for (const [s, o] of Array.from(O.entries()))
|
|
140
|
-
!o.isRunning && o.endTime && t - o.endTime.getTime() > Mt && r.push(s);
|
|
141
|
-
for (const s of r)
|
|
142
|
-
O.delete(s);
|
|
143
|
-
}
|
|
144
|
-
function H(t) {
|
|
145
|
-
const { process: r } = t, s = Date.now();
|
|
146
|
-
if (s - r.lastOutputTime.getTime() >= Tt && (r.output += r.localOutput, r.localOutput = "", r.lastOutputTime = new Date(s), r.output.length > k)) {
|
|
147
|
-
const n = `
|
|
148
|
-
... [${r.output.length - k} characters trimmed] ...
|
|
149
|
-
`, a = k - n.length;
|
|
150
|
-
if (a > 0) {
|
|
151
|
-
const i = Math.floor(a / 2);
|
|
152
|
-
r.output = r.output.substring(0, i) + n + r.output.substring(
|
|
153
|
-
r.output.length - (a - i)
|
|
154
|
-
);
|
|
155
|
-
} else
|
|
156
|
-
r.output = r.output.substring(0, k);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
function Et(t, r) {
|
|
160
|
-
const s = r.limit;
|
|
161
|
-
if (t.length <= s) return t;
|
|
162
|
-
const e = `
|
|
163
|
-
... [${t.length - s} characters trimmed] ...
|
|
164
|
-
`, n = s - e.length;
|
|
165
|
-
if (n <= 0)
|
|
166
|
-
return t.substring(0, s);
|
|
167
|
-
const a = Math.floor(n / 2);
|
|
168
|
-
return t.substring(0, a) + e + t.substring(t.length - (n - a));
|
|
169
|
-
}
|
|
170
|
-
function C(t) {
|
|
171
|
-
return `Invalid arguments: ${t instanceof Error ? t.message : "Unknown error"}.
|
|
172
|
-
|
|
173
|
-
Provide valid parameters according to schema.`;
|
|
174
|
-
}
|
|
175
|
-
const Ie = h.object({
|
|
176
|
-
id: h.number().describe(
|
|
177
|
-
"Process ID to get detailed status information for. Get process IDs using process-list. Works for both running and completed processes. Examples: 1, 42, 123"
|
|
178
|
-
),
|
|
179
|
-
outputLimit: h.number().max(k).default(k).describe(
|
|
180
|
-
`Maximum number of output characters to capture and return from the process. Output exceeding this limit will be truncated with beginning/end preserved and middle removed. Maximum: ${k} characters. Default: ${k}.`
|
|
181
|
-
)
|
|
182
|
-
});
|
|
183
|
-
async function Y(t, r) {
|
|
184
|
-
Q();
|
|
185
|
-
let s;
|
|
186
|
-
try {
|
|
187
|
-
s = Ie.parse(t);
|
|
188
|
-
} catch (u) {
|
|
189
|
-
return {
|
|
190
|
-
error: C(u)
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
const { id: o, outputLimit: e } = s, n = O.get(o);
|
|
194
|
-
if (!n)
|
|
195
|
-
return {
|
|
196
|
-
error: `Process ${o} not found. The process may have already completed and been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`
|
|
197
|
-
};
|
|
198
|
-
H({ process: n });
|
|
199
|
-
const a = n.output + n.localOutput, i = Et(a, { limit: e });
|
|
200
|
-
return n.output = "", n.localOutput = "", {
|
|
201
|
-
id: n.id,
|
|
202
|
-
cwd: T.relative(r.workingDir || "", n.cwd),
|
|
203
|
-
commandLine: n.commandLine,
|
|
204
|
-
pid: n.pid,
|
|
205
|
-
startTime: n.startTime.toISOString().replace(/[TZ]/g, " ").trim(),
|
|
206
|
-
endTime: n.endTime?.toISOString().replace(/[TZ]/g, " ").trim(),
|
|
207
|
-
exitCode: n.exitCode,
|
|
208
|
-
isRunning: n.isRunning,
|
|
209
|
-
output: i,
|
|
210
|
-
error: n.error
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
function Dt(t, r) {
|
|
214
|
-
t(
|
|
215
|
-
"process-status",
|
|
216
|
-
{
|
|
217
|
-
title: "Get Host Machine Process Status",
|
|
218
|
-
description: "Get detailed status information about a process on the host machine. Use this to check if commands completed successfully, get their output, or monitor running processes. The output is cleared after retrieval to prevent duplication in subsequent calls",
|
|
219
|
-
inputSchema: Ie.shape
|
|
220
|
-
},
|
|
221
|
-
async (s) => {
|
|
222
|
-
const o = await Y(s, r);
|
|
223
|
-
if (!("output" in o))
|
|
224
|
-
return `Method: process-status(${JSON.stringify(s)})
|
|
225
|
-
❌ Error: ${o.error}`;
|
|
226
|
-
const e = o.output || "";
|
|
227
|
-
return delete o.output, `Method: process-status(${JSON.stringify(s)})
|
|
228
|
-
${JSON.stringify(o, null, 2)}
|
|
229
|
-
|
|
230
|
-
Output:
|
|
231
|
-
${e.trim()}`;
|
|
232
|
-
}
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
function Me(t) {
|
|
236
|
-
K(t, "SIGTERM", (r) => {
|
|
237
|
-
r && !r.message.includes("not found") && console.error(`Error sending SIGTERM to process ${t}:`, r);
|
|
238
|
-
}), setTimeout(() => {
|
|
239
|
-
K(t, "SIGKILL", (r) => {
|
|
240
|
-
r && !r.message.includes("not found") && console.error(`Error sending SIGKILL to process ${t}:`, r);
|
|
241
|
-
});
|
|
242
|
-
}, vt);
|
|
243
|
-
}
|
|
244
|
-
const Te = h.object({
|
|
245
|
-
id: h.number().describe(
|
|
246
|
-
"Process ID to wait for completion. Get process IDs using process-list. The process can be running or already completed. Examples: 1, 42, 123"
|
|
247
|
-
),
|
|
248
|
-
waitTime: h.number().optional().describe(
|
|
249
|
-
"Maximum time to wait in seconds for process completion. If omitted, waits indefinitely until process completes. If process is already completed, returns immediately. Examples: 30 (wait up to 30 seconds), 300 (wait up to 5 minutes)"
|
|
250
|
-
),
|
|
251
|
-
autoKill: h.boolean().default(!1).describe(
|
|
252
|
-
"Automatically terminate the process if waitTime expires and it is still running. Only applies when waitTime is specified. Default: false (let process continue running after timeout). Set to true for processes that should not run indefinitely"
|
|
253
|
-
),
|
|
254
|
-
outputLimit: h.number().max(k).default(k).describe(
|
|
255
|
-
`Maximum number of output characters to capture and return from the process. Output exceeding this limit will be truncated with beginning/end preserved and middle removed. Maximum: ${k} characters. Default: ${k}.`
|
|
256
|
-
)
|
|
257
|
-
});
|
|
258
|
-
async function ve(t, r) {
|
|
259
|
-
let s;
|
|
260
|
-
try {
|
|
261
|
-
s = Te.parse(t);
|
|
262
|
-
} catch (m) {
|
|
263
|
-
return {
|
|
264
|
-
error: C(m)
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
const { id: o, waitTime: e, autoKill: n, outputLimit: a } = s, i = O.get(o);
|
|
268
|
-
if (!i)
|
|
269
|
-
return {
|
|
270
|
-
error: `Process ${o} not found. The process may have already completed and been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`
|
|
271
|
-
};
|
|
272
|
-
const u = Date.now();
|
|
273
|
-
let c = !1, l = !1;
|
|
274
|
-
e != null && await new Promise((g) => {
|
|
275
|
-
const p = setInterval(() => {
|
|
276
|
-
i.isRunning ? Date.now() - u >= e * 1e3 && (clearInterval(p), c = !0, n && i.pid && (Me(i.pid), l = !0), g()) : (clearInterval(p), g());
|
|
277
|
-
}, 100);
|
|
278
|
-
});
|
|
279
|
-
const f = (Date.now() - u) / 1e3;
|
|
280
|
-
return {
|
|
281
|
-
...await Y({ id: o, outputLimit: a }, r),
|
|
282
|
-
waitDuration: f,
|
|
283
|
-
waitTimeExceeded: c,
|
|
284
|
-
autoKillExecuted: l
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
function Ft(t, r) {
|
|
288
|
-
t(
|
|
289
|
-
"process-wait",
|
|
290
|
-
{
|
|
291
|
-
title: "Wait for Host Machine Process",
|
|
292
|
-
description: "Wait for a host machine process to complete execution, with optional timeout and auto-kill functionality. Use this for long-running commands like builds, installs, or tests when you need final results",
|
|
293
|
-
inputSchema: Te.shape
|
|
294
|
-
},
|
|
295
|
-
async (s) => {
|
|
296
|
-
const o = await ve(s, r);
|
|
297
|
-
if (!("output" in o))
|
|
298
|
-
return `Method: process-wait(${JSON.stringify(s)})
|
|
299
|
-
❌ Error: ${o.error}`;
|
|
300
|
-
const e = o.output || "";
|
|
301
|
-
return delete o.output, `Method: process-wait(${JSON.stringify(s)})
|
|
302
|
-
${JSON.stringify(o, null, 2)}
|
|
303
|
-
|
|
304
|
-
Output:
|
|
305
|
-
${e.trim()}`;
|
|
306
|
-
}
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
const Ce = h.object({
|
|
310
|
-
cwd: h.string().optional().describe(
|
|
311
|
-
'Working directory for command execution, resolved relative to the current working directory. Leave empty to use current directory. Examples: "src" (run in src/ subdirectory), "../parent" (run in parent directory), "build/output" (run in nested subdirectory). Directory must exist'
|
|
312
|
-
),
|
|
313
|
-
commandLine: h.string().describe(
|
|
314
|
-
'Complete command line to execute on the host machine. Include all arguments and options. Examples: "npm install", "pnpm build", "node script.js --verbose", "git status". Command must be in the allowed commands list for security'
|
|
315
|
-
),
|
|
316
|
-
waitTime: h.number().optional().describe(
|
|
317
|
-
"Time to wait in seconds for process completion before returning results. If specified, will wait this long then return final status. If omitted, returns immediately with initial status. Use process-wait or process-status to check progress later. Examples: 30 (wait 30 seconds), 120 (wait 2 minutes)"
|
|
318
|
-
),
|
|
319
|
-
autoKill: h.boolean().default(!1).describe(
|
|
320
|
-
"Automatically kill the process if waitTime expires and it is still running. Only applies when waitTime is specified. Default: false (let process continue running). Set to true for commands that should not run indefinitely"
|
|
321
|
-
),
|
|
322
|
-
outputLimit: h.number().max(k).default(k).describe(
|
|
323
|
-
`Maximum number of output characters to capture and return from the process. Output exceeding this limit will be truncated with beginning/end preserved and middle removed. Maximum: ${k} characters. Default: ${k}.`
|
|
324
|
-
)
|
|
325
|
-
});
|
|
326
|
-
async function Bt(t, r) {
|
|
327
|
-
Q();
|
|
328
|
-
let s;
|
|
329
|
-
try {
|
|
330
|
-
s = Ce.parse(t);
|
|
331
|
-
} catch (d) {
|
|
332
|
-
return {
|
|
333
|
-
error: C(d)
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
const { commandLine: o, waitTime: e, autoKill: n, outputLimit: a } = s, { commandLineRules: i } = r, u = T.resolve(r.workingDir || "", s.cwd || "");
|
|
337
|
-
if (!Ct({ commandLine: o, commandLineRules: i })) {
|
|
338
|
-
const d = i.map(
|
|
339
|
-
(m) => `${m.rule.toUpperCase()}: /${m.regexp}/ (${m.note})`
|
|
340
|
-
).join(`
|
|
341
|
-
`);
|
|
342
|
-
return {
|
|
343
|
-
error: `Command line not allowed: "${o}". For security, command lines are validated against configured rules in order. Command line was denied by the rule evaluation. Current command line rules:
|
|
344
|
-
${d}
|
|
345
|
-
|
|
346
|
-
To use this command line, ask the user to modify the command line rules in the configuration.`
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
if (Array.from(O.values()).filter(
|
|
350
|
-
(d) => d.isRunning
|
|
351
|
-
).length >= ie)
|
|
352
|
-
return {
|
|
353
|
-
error: `Maximum concurrent process limit reached (${ie} processes). Cannot start new process until existing processes complete. Use process-list to see active processes, or process-kill to terminate unnecessary processes.`
|
|
354
|
-
};
|
|
355
|
-
const l = kt(), f = {
|
|
356
|
-
id: l,
|
|
357
|
-
cwd: u,
|
|
358
|
-
commandLine: o,
|
|
359
|
-
startTime: /* @__PURE__ */ new Date(),
|
|
360
|
-
isRunning: !0,
|
|
361
|
-
output: "",
|
|
362
|
-
localOutput: "",
|
|
363
|
-
lastOutputTime: /* @__PURE__ */ new Date()
|
|
364
|
-
};
|
|
365
|
-
O.set(l, f);
|
|
366
|
-
try {
|
|
367
|
-
const d = ct(o, [], {
|
|
368
|
-
shell: !0,
|
|
369
|
-
cwd: u,
|
|
370
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
371
|
-
});
|
|
372
|
-
f.pid = d.pid;
|
|
373
|
-
const m = (g) => {
|
|
374
|
-
const p = g.toString();
|
|
375
|
-
f.localOutput += p, H({ process: f }), console.log(p);
|
|
376
|
-
};
|
|
377
|
-
return d.stdout?.on("data", m), d.stderr?.on("data", m), d.on("close", (g) => {
|
|
378
|
-
if (f.isRunning = !1, f.endTime = /* @__PURE__ */ new Date(), f.exitCode = g !== null ? g : void 0, f.output += f.localOutput, f.localOutput = "", f.output.length > k) {
|
|
379
|
-
const y = `
|
|
380
|
-
... [${f.output.length - k} characters trimmed] ...
|
|
381
|
-
`, w = k - y.length;
|
|
382
|
-
if (w > 0) {
|
|
383
|
-
const S = Math.floor(w / 2);
|
|
384
|
-
f.output = f.output.substring(0, S) + y + f.output.substring(
|
|
385
|
-
f.output.length - (w - S)
|
|
386
|
-
);
|
|
387
|
-
} else
|
|
388
|
-
f.output = f.output.substring(0, k);
|
|
389
|
-
}
|
|
390
|
-
console.log(`Process ${l} (${o}) exited with code ${g}`);
|
|
391
|
-
}), d.on("error", (g) => {
|
|
392
|
-
f.isRunning = !1, f.endTime = /* @__PURE__ */ new Date(), f.error = g.message, console.error(`Process ${l} error:`, g.message);
|
|
393
|
-
}), e != null ? ve({ id: l, waitTime: e, autoKill: n, outputLimit: a }, r) : Y({ id: l, outputLimit: a }, r);
|
|
394
|
-
} catch (d) {
|
|
395
|
-
return f.isRunning = !1, f.endTime = /* @__PURE__ */ new Date(), f.error = d instanceof Error ? d.message : "Unknown error", { error: f.error };
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
function Ot(t, r) {
|
|
399
|
-
const s = r.commandLineRules.map((o) => `${o.rule.toUpperCase()}: ${o.regexp} (${o.note})`).join(`
|
|
400
|
-
`);
|
|
401
|
-
t(
|
|
402
|
-
"process-run",
|
|
403
|
-
{
|
|
404
|
-
title: "Execute Command Line on Host Machine",
|
|
405
|
-
description: `Execute command lines on the host machine. Use this to build, test, lint, install packages, or run system commands. Prefer process-run with waitTime parameter if you need to immediately execute and wait for completion, instead of separate process-run and process-wait calls. Security: Command lines are validated against configured rules processed in order (later rules override earlier ones). Current command line rules:
|
|
406
|
-
${s}`,
|
|
407
|
-
inputSchema: Ce.shape
|
|
408
|
-
},
|
|
409
|
-
async (o) => {
|
|
410
|
-
const e = await Bt(o, r);
|
|
411
|
-
if (!("output" in e))
|
|
412
|
-
return `Method: process-run(${JSON.stringify(o)})
|
|
413
|
-
❌ Error: ${e.error}`;
|
|
414
|
-
const n = e.output || "";
|
|
415
|
-
return delete e.output, `Method: process-run(${JSON.stringify(o)})
|
|
416
|
-
${JSON.stringify(e, null, 2)}
|
|
417
|
-
|
|
418
|
-
Output:
|
|
419
|
-
${n.trim()}`;
|
|
420
|
-
}
|
|
421
|
-
);
|
|
422
|
-
}
|
|
423
|
-
const ke = h.object({
|
|
424
|
-
minOpenDateTime: h.string().optional().describe(
|
|
425
|
-
'Filter to processes started after this datetime. Accepts ISO format or space-separated format. Examples: "2024-01-15T10:30:00Z", "2024-01-15 10:30:00". Underscores and spaces are converted to standard ISO format internally'
|
|
426
|
-
),
|
|
427
|
-
minCloseDateTime: h.string().optional().describe(
|
|
428
|
-
'Filter to processes that finished after this datetime. Only applies to completed processes. Accepts ISO format or space-separated format. Examples: "2024-01-15T14:30:00Z", "2024-01-15 14:30:00". Useful for finding recently completed processes'
|
|
429
|
-
),
|
|
430
|
-
activeOnly: h.boolean().default(!1).describe(
|
|
431
|
-
"Show only currently running processes. Set to true to exclude completed processes, false to show all processes (running and completed). Default: false (show all)"
|
|
432
|
-
),
|
|
433
|
-
fields: h.array(h.string()).optional().describe(
|
|
434
|
-
'Specific process data fields to include in the response. If omitted, returns all available fields. Available fields: id, cwd, commandLine, pid, startTime, endTime, exitCode, isRunning, output, error. Examples: ["id", "commandLine", "isRunning"] for minimal info, ["id", "output", "exitCode"] for execution results'
|
|
435
|
-
)
|
|
436
|
-
});
|
|
437
|
-
async function Rt(t, r) {
|
|
438
|
-
Q();
|
|
439
|
-
let s;
|
|
440
|
-
try {
|
|
441
|
-
s = ke.parse(t);
|
|
442
|
-
} catch (c) {
|
|
443
|
-
return {
|
|
444
|
-
error: C(c)
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
const { minOpenDateTime: o, minCloseDateTime: e, activeOnly: n, fields: a } = s;
|
|
448
|
-
let i = Array.from(O.values());
|
|
449
|
-
if (o) {
|
|
450
|
-
const c = new Date(o.replace(/[_\s]/g, "T"));
|
|
451
|
-
i = i.filter((l) => l.startTime >= c);
|
|
452
|
-
}
|
|
453
|
-
if (e) {
|
|
454
|
-
const c = new Date(e.replace(/[_\s]/g, "T"));
|
|
455
|
-
i = i.filter((l) => l.endTime && l.endTime >= c);
|
|
456
|
-
}
|
|
457
|
-
return n && (i = i.filter((c) => c.isRunning)), { processes: i.map((c) => {
|
|
458
|
-
H({ process: c });
|
|
459
|
-
let l = {
|
|
460
|
-
id: c.id,
|
|
461
|
-
cwd: it.relative(r.workingDir || "", c.cwd),
|
|
462
|
-
commandLine: c.commandLine,
|
|
463
|
-
pid: c.pid,
|
|
464
|
-
startTime: c.startTime.toISOString().replace(/[TZ]/g, " ").trim(),
|
|
465
|
-
endTime: c.endTime?.toISOString().replace(/[TZ]/g, " ").trim(),
|
|
466
|
-
exitCode: c.exitCode,
|
|
467
|
-
isRunning: c.isRunning,
|
|
468
|
-
output: c.output + c.localOutput,
|
|
469
|
-
error: c.error
|
|
470
|
-
};
|
|
471
|
-
if (a) {
|
|
472
|
-
const f = {};
|
|
473
|
-
for (const d of a)
|
|
474
|
-
d in l && (f[d] = l[d]);
|
|
475
|
-
l = f;
|
|
476
|
-
}
|
|
477
|
-
return l;
|
|
478
|
-
}) };
|
|
479
|
-
}
|
|
480
|
-
function Pt(t, r) {
|
|
481
|
-
t(
|
|
482
|
-
"process-list",
|
|
483
|
-
{
|
|
484
|
-
title: "List Host Machine Processes",
|
|
485
|
-
description: "List all processes that have been executed on the host machine. Use this to see running processes, check command history, or find process IDs for status/wait operations",
|
|
486
|
-
inputSchema: ke.shape
|
|
487
|
-
},
|
|
488
|
-
async (s) => {
|
|
489
|
-
const o = await Rt(s, r);
|
|
490
|
-
if (o.error != null)
|
|
491
|
-
return `Method: process-list(${JSON.stringify(s)})
|
|
492
|
-
❌ Error: ${o.error}`;
|
|
493
|
-
const e = o.processes.map(
|
|
494
|
-
(n) => `[${n.isRunning ? "RUNNING" : "COMPLETED"}] ${n.id}: ${n.commandLine}`
|
|
495
|
-
).join(`
|
|
496
|
-
`) || "No processes found";
|
|
497
|
-
return `Method: process-list(${JSON.stringify(s)})
|
|
498
|
-
Processes:
|
|
499
|
-
${e}`;
|
|
500
|
-
}
|
|
501
|
-
);
|
|
502
|
-
}
|
|
503
|
-
const Ne = h.object({
|
|
504
|
-
id: h.number().describe(
|
|
505
|
-
"Process ID of the process to terminate. Get process IDs using process-list. The process must be currently running. Examples: 1, 42, 123"
|
|
506
|
-
)
|
|
507
|
-
});
|
|
508
|
-
function zt(t) {
|
|
509
|
-
let r;
|
|
510
|
-
try {
|
|
511
|
-
r = Ne.parse(t);
|
|
512
|
-
} catch (e) {
|
|
513
|
-
return {
|
|
514
|
-
error: C(e)
|
|
515
|
-
};
|
|
516
|
-
}
|
|
517
|
-
const { id: s } = r, o = O.get(s);
|
|
518
|
-
if (!o)
|
|
519
|
-
return {
|
|
520
|
-
error: `Process ${s} not found. The process may have already completed, been cleaned up after 30 minutes, or the ID may be incorrect. Use process-list to see available processes and their current status.`
|
|
521
|
-
};
|
|
522
|
-
if (!o.isRunning)
|
|
523
|
-
return {
|
|
524
|
-
error: `Process ${s} is not currently running. The process has already completed or was previously terminated. Use process-list to see the process status and process-status to get final execution details.`
|
|
525
|
-
};
|
|
526
|
-
if (!o.pid)
|
|
527
|
-
return {
|
|
528
|
-
error: `Process ${s} has no system process ID (PID). This indicates the process failed to start properly or the system was unable to assign a PID. Check process-status for error details.`
|
|
529
|
-
};
|
|
530
|
-
try {
|
|
531
|
-
return Me(o.pid), { success: !0, message: `Kill signal sent to process ${s}` };
|
|
532
|
-
} catch (e) {
|
|
533
|
-
return {
|
|
534
|
-
error: `Failed to terminate process ${s}: ${e instanceof Error ? e.message : "Unknown error"}. The process may have already exited, be protected by the system, or there may be insufficient permissions. Use process-status to check current process state.`
|
|
535
|
-
};
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
function Lt(t, r) {
|
|
539
|
-
t(
|
|
540
|
-
"process-kill",
|
|
541
|
-
{
|
|
542
|
-
title: "Kill Host Machine Process",
|
|
543
|
-
description: "Forcibly terminate a running process on the host machine. Use this to stop runaway processes, hung commands, or long-running tasks that need to be cancelled",
|
|
544
|
-
inputSchema: Ne.shape
|
|
545
|
-
},
|
|
546
|
-
async (s) => {
|
|
547
|
-
const o = zt(s);
|
|
548
|
-
return o.error != null ? `Method: process-kill(${JSON.stringify(s)})
|
|
549
|
-
❌ Error: ${o.error}` : `Method: process-kill(${JSON.stringify(s)})
|
|
550
|
-
${JSON.stringify(o, null, 2)}`;
|
|
551
|
-
}
|
|
552
|
-
);
|
|
553
|
-
}
|
|
554
|
-
function Ut(t, r) {
|
|
555
|
-
Nt(), r.run && Ot(t, r), r.status && Dt(t, r), r.wait && Ft(t, r), r.list && Pt(t, r), r.kill && Lt(t);
|
|
556
|
-
const s = r.commandLineRules?.map(
|
|
557
|
-
(o) => `${o.rule.toUpperCase()}: ${o.regexp} (${o.note})`
|
|
558
|
-
) || [];
|
|
559
|
-
console.log(
|
|
560
|
-
`Process manager:
|
|
561
|
-
- Working directory: ${T.resolve(r.workingDir || "")}
|
|
562
|
-
- Command line rules: ${r.commandLineRules?.length || 0} rules configured:
|
|
563
|
-
${s.map((o) => `- ${o}`).join(`
|
|
564
|
-
`)}
|
|
565
|
-
`
|
|
566
|
-
);
|
|
567
|
-
}
|
|
568
|
-
function At(t, r) {
|
|
569
|
-
return function(o, e, n) {
|
|
570
|
-
const a = async (...i) => {
|
|
571
|
-
await q({
|
|
572
|
-
logFilePath: r.logFilePath,
|
|
573
|
-
message: "REQUEST",
|
|
574
|
-
data: { name: o, args: i }
|
|
575
|
-
});
|
|
576
|
-
const u = await n(...i);
|
|
577
|
-
return await q({
|
|
578
|
-
logFilePath: r.logFilePath,
|
|
579
|
-
message: "RESPONSE",
|
|
580
|
-
data: u
|
|
581
|
-
}), {
|
|
582
|
-
content: [
|
|
583
|
-
{
|
|
584
|
-
type: "text",
|
|
585
|
-
text: u
|
|
586
|
-
}
|
|
587
|
-
]
|
|
588
|
-
};
|
|
589
|
-
};
|
|
590
|
-
return t.registerTool(
|
|
591
|
-
o,
|
|
592
|
-
e,
|
|
593
|
-
a
|
|
594
|
-
);
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
function qt(t) {
|
|
598
|
-
return t.match(/^[/\\]?[^/\\]+/)[0];
|
|
599
|
-
}
|
|
600
|
-
function Gt(t, r) {
|
|
601
|
-
return qt(t) + "|" + r.ino;
|
|
602
|
-
}
|
|
603
|
-
function jt(t) {
|
|
604
|
-
return t.endsWith(":") && (t += "/"), T.resolve(t);
|
|
605
|
-
}
|
|
606
|
-
const Ee = new lt(ft.cpus().length);
|
|
607
|
-
function ce(t, r) {
|
|
608
|
-
t.totalSize += r.totalSize, t.maxFileDateModified = Math.max(
|
|
609
|
-
t.maxFileDateModified,
|
|
610
|
-
r.maxFileDateModified
|
|
611
|
-
), t.countFiles += r.countFiles, t.countDirs += r.countDirs, t.countLinks += r.countLinks;
|
|
612
|
-
}
|
|
613
|
-
const _t = function(r) {
|
|
614
|
-
return r.code === "ENOENT";
|
|
615
|
-
};
|
|
616
|
-
function De(t) {
|
|
617
|
-
const r = t.paths;
|
|
618
|
-
if (!r || r.length === 0)
|
|
619
|
-
return Promise.resolve({
|
|
620
|
-
totalSize: 0,
|
|
621
|
-
maxFileDateModified: 0,
|
|
622
|
-
countFiles: 0,
|
|
623
|
-
countDirs: 0,
|
|
624
|
-
countLinks: 0
|
|
625
|
-
});
|
|
626
|
-
const s = t.level ?? 0, o = t.walkedIds ?? /* @__PURE__ */ new Set(), e = t.abortSignal, n = t.pool ?? Ee, a = t.handleError, i = t.priority ?? P(0), u = t.walkLinks ?? !1, c = t.log, l = t.handlePath, f = t.matchPath;
|
|
627
|
-
async function d(g) {
|
|
628
|
-
if (!(a && await a(g)) && !_t(g))
|
|
629
|
-
throw g;
|
|
630
|
-
}
|
|
631
|
-
function m(g) {
|
|
632
|
-
return !(!c || c.minTotalContentSize != null && g < c.minTotalContentSize || c.maxNestedLevel != null && s > c.maxNestedLevel);
|
|
633
|
-
}
|
|
634
|
-
return ut(async (g) => {
|
|
635
|
-
const p = dt(e, g), y = {
|
|
636
|
-
totalSize: 0,
|
|
637
|
-
maxFileDateModified: 0,
|
|
638
|
-
countFiles: 0,
|
|
639
|
-
countDirs: 0,
|
|
640
|
-
countLinks: 0
|
|
641
|
-
};
|
|
642
|
-
function w(b, x) {
|
|
643
|
-
if (m(x.totalSize)) {
|
|
644
|
-
const v = `${x.totalSize.toLocaleString("en-US").replace(/,/g, " ").padStart(19)}: ${b}`;
|
|
645
|
-
c?.handleLog ? c.handleLog(v) : console.log(v);
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
async function S(b, x, $, v) {
|
|
649
|
-
return l ? await z({
|
|
650
|
-
pool: n,
|
|
651
|
-
func: async () => {
|
|
652
|
-
try {
|
|
653
|
-
return await l({
|
|
654
|
-
level: s,
|
|
655
|
-
path: b,
|
|
656
|
-
stat: x,
|
|
657
|
-
itemStat: $,
|
|
658
|
-
totalStat: y,
|
|
659
|
-
abortSignal: p
|
|
660
|
-
});
|
|
661
|
-
} catch (E) {
|
|
662
|
-
return await d(E), !1;
|
|
663
|
-
}
|
|
664
|
-
},
|
|
665
|
-
count: 1,
|
|
666
|
-
priority: v,
|
|
667
|
-
abortSignal: p
|
|
668
|
-
}) : !0;
|
|
669
|
-
}
|
|
670
|
-
async function M(b, x, $, v) {
|
|
671
|
-
v || (v = b);
|
|
672
|
-
const E = await z({
|
|
673
|
-
pool: n,
|
|
674
|
-
func: () => B.promises.lstat(b).catch(d),
|
|
675
|
-
count: 1,
|
|
676
|
-
priority: P(x, P(1, i)),
|
|
677
|
-
abortSignal: p
|
|
678
|
-
});
|
|
679
|
-
if (!E || !$ && E.isFile())
|
|
680
|
-
return null;
|
|
681
|
-
const ne = Gt(b, E);
|
|
682
|
-
if (o.has(ne))
|
|
683
|
-
return null;
|
|
684
|
-
o.add(ne);
|
|
685
|
-
let N = {
|
|
686
|
-
totalSize: E.size,
|
|
687
|
-
maxFileDateModified: E.isDirectory() ? 0 : E.mtimeMs,
|
|
688
|
-
countFiles: 0,
|
|
689
|
-
countDirs: 0,
|
|
690
|
-
countLinks: 0
|
|
691
|
-
};
|
|
692
|
-
const L = P(
|
|
693
|
-
x,
|
|
694
|
-
P(E.isDirectory() ? 2 : 3, i)
|
|
695
|
-
);
|
|
696
|
-
if (E.isSymbolicLink()) {
|
|
697
|
-
if (u) {
|
|
698
|
-
const F = await z({
|
|
699
|
-
pool: n,
|
|
700
|
-
func: () => B.promises.readlink(b).catch(d).then((R) => R ?? null),
|
|
701
|
-
count: 1,
|
|
702
|
-
priority: L,
|
|
703
|
-
abortSignal: p
|
|
704
|
-
});
|
|
705
|
-
if (F) {
|
|
706
|
-
const R = T.isAbsolute(F) ? F : T.resolve(T.dirname(v), F), U = await M(
|
|
707
|
-
R,
|
|
708
|
-
x,
|
|
709
|
-
$,
|
|
710
|
-
v
|
|
711
|
-
);
|
|
712
|
-
U && (N = U);
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
return ($ || N.countFiles + N.countDirs + N.countLinks >= 1) && (N.countLinks += 1, await S(
|
|
716
|
-
v,
|
|
717
|
-
E,
|
|
718
|
-
N,
|
|
719
|
-
L
|
|
720
|
-
) && (ce(y, N), w(v, N))), N;
|
|
721
|
-
} else if (E.isDirectory()) {
|
|
722
|
-
const F = await z({
|
|
723
|
-
pool: n,
|
|
724
|
-
func: () => B.promises.readdir(b).catch(d),
|
|
725
|
-
count: 1,
|
|
726
|
-
priority: i,
|
|
727
|
-
abortSignal: p
|
|
728
|
-
});
|
|
729
|
-
if (F) {
|
|
730
|
-
for (let R = 0, U = F.length; R < U; R++)
|
|
731
|
-
F[R] = T.join(v, F[R]);
|
|
732
|
-
N = await De({
|
|
733
|
-
...t,
|
|
734
|
-
paths: F,
|
|
735
|
-
abortSignal: p,
|
|
736
|
-
priority: L,
|
|
737
|
-
level: s + 1,
|
|
738
|
-
walkedIds: o
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
return ($ || N.countFiles + N.countDirs + N.countLinks >= 1) && (E.isDirectory() ? N.countDirs += 1 : E.isFile() && (N.countFiles += 1), await S(
|
|
743
|
-
v,
|
|
744
|
-
E,
|
|
745
|
-
N,
|
|
746
|
-
L
|
|
747
|
-
) && (ce(y, N), w(v, N))), N;
|
|
748
|
-
}
|
|
749
|
-
const I = [];
|
|
750
|
-
for (let b = 0, x = r.length; b < x; b++) {
|
|
751
|
-
const $ = jt(r[b]), v = f ? f($) : !0;
|
|
752
|
-
v !== !1 && I.push(M($, b, v));
|
|
753
|
-
}
|
|
754
|
-
return await Promise.all(I), y;
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
function Fe(t) {
|
|
758
|
-
return De(t);
|
|
759
|
-
}
|
|
760
|
-
function Jt(t, r) {
|
|
761
|
-
if (!r || r === ".")
|
|
762
|
-
return t;
|
|
763
|
-
const s = t.startsWith("^");
|
|
764
|
-
s && (t = t.substring(1));
|
|
765
|
-
const o = t.startsWith("!");
|
|
766
|
-
return o && (t = t.substring(1)), t.startsWith("/") ? (r.endsWith("/") && (r = r.substring(0, r.length - 1)), t = r + t) : (r.endsWith("/") || (r += "/"), t.startsWith("./") ? t = r + t.substring(2) : t.startsWith("../") ? t = r + t : (r.startsWith("..") && (r = ""), t.startsWith("**") ? t = r + t : t = r + "**/" + t)), t = T.normalize(t).replace(/\\/g, "/"), o && (t = "!" + t), s && (t = "^" + t), t;
|
|
767
|
-
}
|
|
768
|
-
function Kt(t) {
|
|
769
|
-
const r = t.startsWith("!");
|
|
770
|
-
return r && (t = t.substring(1)), t.startsWith("/") ? t = t.substring(1) : !t.startsWith("**") && !t.startsWith("../") && (t = `**/${t}`), r && (t = "!" + t), t;
|
|
771
|
-
}
|
|
772
|
-
function le(t) {
|
|
773
|
-
return "^" + t;
|
|
774
|
-
}
|
|
775
|
-
async function Wt(t) {
|
|
776
|
-
const s = (await B.promises.readFile(t, "utf-8")).split(`
|
|
777
|
-
`), o = [];
|
|
778
|
-
return s.forEach((e) => {
|
|
779
|
-
e = e.trim(), !(!e || e.startsWith("#")) && o.push(e);
|
|
780
|
-
}), o;
|
|
781
|
-
}
|
|
782
|
-
async function Be(t) {
|
|
783
|
-
const r = t.rootDir ?? ".", s = [];
|
|
784
|
-
if (!t.globs?.length)
|
|
785
|
-
return s;
|
|
786
|
-
const o = [];
|
|
787
|
-
return t.globs.forEach((e) => {
|
|
788
|
-
e.value && (e.valueType === "file-contains-patterns" ? o.push(e) : e.valueType === "pattern" && s.push(e.exclude ? le(e.value) : e.value));
|
|
789
|
-
}), o.length && await Promise.all(
|
|
790
|
-
o.map(async (e) => {
|
|
791
|
-
await z({
|
|
792
|
-
pool: Ee,
|
|
793
|
-
count: 1,
|
|
794
|
-
func: async () => {
|
|
795
|
-
const n = T.resolve(r, e.value), a = await Wt(n), i = T.relative(r, T.dirname(n));
|
|
796
|
-
a.forEach((u) => {
|
|
797
|
-
u = Kt(u), u = Jt(u, i), s.push(e.exclude ? le(u) : u);
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
});
|
|
801
|
-
})
|
|
802
|
-
), s;
|
|
803
|
-
}
|
|
804
|
-
function Oe({
|
|
805
|
-
globs: t,
|
|
806
|
-
rootDir: r,
|
|
807
|
-
noCase: s
|
|
808
|
-
}) {
|
|
809
|
-
const o = [];
|
|
810
|
-
return t.forEach((e) => {
|
|
811
|
-
e = e.replace(/\\/g, "/").trim();
|
|
812
|
-
const n = e.startsWith("^");
|
|
813
|
-
n && (e = e.substring(1).trim());
|
|
814
|
-
const a = e.startsWith("!");
|
|
815
|
-
if (a && (e = e.substring(1).trim()), e.startsWith("!") || e.startsWith("^"))
|
|
816
|
-
throw new Error(
|
|
817
|
-
`Invalid glob pattern: "${e}". The syntax '${e.substring(0, 2)}' is not supported. Valid glob patterns use: * (match any characters), ** (match any directories), ? (match single character), [abc] (character class), ! (negate pattern), ^ (exclude if included). Examples of valid patterns: "*.js", "src/**/*.ts", "!node_modules", "^dist". Avoid starting with '!' after '^' or multiple special prefixes.`
|
|
818
|
-
);
|
|
819
|
-
e.startsWith("/") && (e = "." + e);
|
|
820
|
-
const i = r ? T.resolve(r, e).replace(/\\/g, "/") : e.replace(/\\/g, "/");
|
|
821
|
-
if (!i)
|
|
822
|
-
return;
|
|
823
|
-
let u;
|
|
824
|
-
try {
|
|
825
|
-
u = mt(i, {
|
|
826
|
-
nocase: s ?? !1,
|
|
827
|
-
dot: !0,
|
|
828
|
-
strictBrackets: !0
|
|
829
|
-
// Validate bracket balance for patterns like "["
|
|
830
|
-
});
|
|
831
|
-
} catch (c) {
|
|
832
|
-
throw new Error(
|
|
833
|
-
`Invalid glob pattern: "${e}". ${c instanceof Error ? c.message : "Unknown error"}. Valid glob patterns use: * (match any characters), ** (match any directories), ? (match single character), [abc] (character class with balanced brackets), ! (negate pattern), ^ (exclude if included). Examples: "*.js", "src/**/*.ts", "!node_modules", "[abc]def.txt". Ensure all brackets [ ] are properly closed and balanced.`
|
|
834
|
-
);
|
|
835
|
-
}
|
|
836
|
-
o.push({
|
|
837
|
-
exclude: n,
|
|
838
|
-
negative: a,
|
|
839
|
-
debugInfo: i,
|
|
840
|
-
match: u
|
|
841
|
-
});
|
|
842
|
-
}), function(n) {
|
|
843
|
-
n = n.replace(/\\/g, "/");
|
|
844
|
-
let a = null, i = !1;
|
|
845
|
-
for (let u = 0, c = o.length; u < c; u++) {
|
|
846
|
-
const l = o[u];
|
|
847
|
-
l.match(n) && (l.exclude ? i = !l.negative : (a = !l.negative, i = !1));
|
|
848
|
-
}
|
|
849
|
-
return i ? !1 : a;
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
async function Qt(t) {
|
|
853
|
-
const r = t.rootDir ?? ".", s = [], o = {};
|
|
854
|
-
t.result.countFiles && (o.countFiles = 0), t.result.size && (o.size = 0);
|
|
855
|
-
const e = await Be({
|
|
856
|
-
rootDir: r,
|
|
857
|
-
globs: t.globs
|
|
858
|
-
});
|
|
859
|
-
return await Fe({
|
|
860
|
-
paths: [r],
|
|
861
|
-
walkLinks: !0,
|
|
862
|
-
matchPath: Oe({
|
|
863
|
-
globs: e,
|
|
864
|
-
rootDir: r,
|
|
865
|
-
noCase: !0
|
|
866
|
-
}),
|
|
867
|
-
handlePath: async ({ path: n, stat: a, itemStat: i }) => {
|
|
868
|
-
const u = T.relative(r, n), c = a.isDirectory(), l = a.isFile();
|
|
869
|
-
if (!c && !l)
|
|
870
|
-
return !0;
|
|
871
|
-
const f = (u || ".").replace(/\\/g, "/"), d = c ? "dir" : "file", m = c ? i.maxFileDateModified || null : a.mtimeMs, g = c ? i.totalSize : a.size, p = c ? i.countFiles : null, y = {
|
|
872
|
-
path: f,
|
|
873
|
-
type: d
|
|
874
|
-
};
|
|
875
|
-
if (t.result.dateModified && (y.dateModified = m), t.result.size && (y.size = g), t.result.countFiles && (y.countFiles = p), t.dateModified && m != null) {
|
|
876
|
-
const [w, S] = t.dateModified;
|
|
877
|
-
if (w != null && m < w || S != null && m > S)
|
|
878
|
-
return !1;
|
|
879
|
-
}
|
|
880
|
-
if (t.totalSize && g != null) {
|
|
881
|
-
const [w, S] = t.totalSize;
|
|
882
|
-
if (w != null && g < w || S != null && g > S)
|
|
883
|
-
return !1;
|
|
884
|
-
}
|
|
885
|
-
return d === "file" && (o.countFiles = (o.countFiles ?? 0) + 1), d === "file" && g != null && (o.size = (o.size ?? 0) + g), m != null && (o.dateModified == null || m > o.dateModified) && (o.dateModified = m), c && !t.result.dirs || l && !t.result.files || s.push(y), !0;
|
|
886
|
-
}
|
|
887
|
-
}), { items: s, totals: o };
|
|
888
|
-
}
|
|
889
|
-
const ue = ["B", "KB", "MB", "GB", "TB"], de = 1024;
|
|
890
|
-
function fe(t) {
|
|
891
|
-
if (t == null) return "-";
|
|
892
|
-
let r = t ?? 0, s = 0;
|
|
893
|
-
for (; r >= de && s < ue.length - 1; )
|
|
894
|
-
r /= de, s++;
|
|
895
|
-
return `${s === 0 ? r.toString() : r.toFixed(2)}${ue[s]}`;
|
|
896
|
-
}
|
|
897
|
-
function me(t) {
|
|
898
|
-
const s = Date.now() - t;
|
|
899
|
-
if (s < 0) return "0s";
|
|
900
|
-
const o = Math.floor(s / 1e3), e = Math.floor(o / 60), n = Math.floor(e / 60), a = Math.floor(n / 24), i = Math.floor(a / 7), u = Math.floor(a / 30), c = Math.floor(a / 365);
|
|
901
|
-
return c > 0 ? `${c}Y` : u > 0 ? `${u}M` : i > 0 ? `${i}w` : a > 0 ? `${a}d` : n > 0 ? `${n}h` : e > 0 ? `${e}m` : `${o}s`;
|
|
902
|
-
}
|
|
903
|
-
function Ht(t, r) {
|
|
904
|
-
return r?.length ? [...t].sort((s, o) => {
|
|
905
|
-
for (let e = 0, n = r.length; e < n; e++) {
|
|
906
|
-
const a = r[e];
|
|
907
|
-
let i, u;
|
|
908
|
-
switch (a.field) {
|
|
909
|
-
case "type":
|
|
910
|
-
i = s.type, u = o.type;
|
|
911
|
-
break;
|
|
912
|
-
case "path":
|
|
913
|
-
i = s.path, u = o.path;
|
|
914
|
-
break;
|
|
915
|
-
case "dateModified":
|
|
916
|
-
i = s.dateModified, u = o.dateModified;
|
|
917
|
-
break;
|
|
918
|
-
case "size":
|
|
919
|
-
i = s.size, u = o.size;
|
|
920
|
-
break;
|
|
921
|
-
case "countFiles":
|
|
922
|
-
i = s.countFiles, u = o.countFiles;
|
|
923
|
-
break;
|
|
924
|
-
}
|
|
925
|
-
if (i == null) {
|
|
926
|
-
if (u == null)
|
|
927
|
-
continue;
|
|
928
|
-
return 1;
|
|
929
|
-
}
|
|
930
|
-
if (u == null)
|
|
931
|
-
return -1;
|
|
932
|
-
const c = i > u ? 1 : i < u ? -1 : 0;
|
|
933
|
-
if (c !== 0)
|
|
934
|
-
return a.desc ? -c : c;
|
|
935
|
-
}
|
|
936
|
-
return 0;
|
|
937
|
-
}) : t;
|
|
938
|
-
}
|
|
939
|
-
function Yt(t, r) {
|
|
940
|
-
const s = Ht(t.items, r.sort ?? []), o = r.fields && r.fields.length > 0 ? r.fields : [];
|
|
941
|
-
let e = "";
|
|
942
|
-
if (s.length > 0 && o.length > 0) {
|
|
943
|
-
for (let n = 0, a = o.length; n < a; n++) {
|
|
944
|
-
const i = o[n];
|
|
945
|
-
switch (n > 0 && (e += " | "), i) {
|
|
946
|
-
case "dateModified":
|
|
947
|
-
e += "Time ago (s/m/h/d/w/M/Y)";
|
|
948
|
-
break;
|
|
949
|
-
case "size":
|
|
950
|
-
e += "Size (B/KB/MB/TB)";
|
|
951
|
-
break;
|
|
952
|
-
case "type":
|
|
953
|
-
e += "Type";
|
|
954
|
-
break;
|
|
955
|
-
case "path":
|
|
956
|
-
e += "Path";
|
|
957
|
-
break;
|
|
958
|
-
case "countFiles":
|
|
959
|
-
e += "Files Count";
|
|
960
|
-
break;
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
for (let n = 0, a = s.length; n < a; n++) {
|
|
964
|
-
const i = s[n];
|
|
965
|
-
e += `
|
|
966
|
-
`;
|
|
967
|
-
for (let u = 0, c = o.length; u < c; u++) {
|
|
968
|
-
const l = o[u];
|
|
969
|
-
switch (u > 0 && (e += " | "), l) {
|
|
970
|
-
case "dateModified":
|
|
971
|
-
e += i.dateModified ? me(i.dateModified) : "-";
|
|
972
|
-
break;
|
|
973
|
-
case "size":
|
|
974
|
-
e += fe(i.size);
|
|
975
|
-
break;
|
|
976
|
-
case "type":
|
|
977
|
-
e += i.type;
|
|
978
|
-
break;
|
|
979
|
-
case "path":
|
|
980
|
-
e += i.type === "dir" ? `${i.path}/` : i.path;
|
|
981
|
-
break;
|
|
982
|
-
case "countFiles":
|
|
983
|
-
i.type === "dir" ? e += i.countFiles != null ? i.countFiles.toString() : "-" : e += "-";
|
|
984
|
-
break;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
{
|
|
990
|
-
e.length > 0 && (e += `
|
|
991
|
-
---
|
|
992
|
-
`);
|
|
993
|
-
const n = fe(t.totals.size ?? 0), a = t.totals.dateModified ? `, last modified ${me(t.totals.dateModified)} ago` : "";
|
|
994
|
-
e += `Totals: ${t.totals.countFiles ?? 0} files in dirs, ${n}${a}`;
|
|
995
|
-
}
|
|
996
|
-
return e;
|
|
997
|
-
}
|
|
998
|
-
const Vt = "3.0.8", Zt = {
|
|
999
|
-
version: Vt
|
|
1000
|
-
}, ds = "Project Tools", fs = "project-tools", ms = Zt.version, hs = "d00f70240703039df14c76176a055bce6b5484d2b552ba2c89820f03b8e5e60d", he = 25e3;
|
|
1001
|
-
function pe(t) {
|
|
1002
|
-
const r = t.match(
|
|
1003
|
-
/^\s*(\d+(?:\.\d+)?)\s*([smhdwMY]|sec(onds?)?|min(utes?)?|hours?|days?|weeks?|months?|years?)\s*$/i
|
|
1004
|
-
);
|
|
1005
|
-
if (!r)
|
|
1006
|
-
throw new Error(
|
|
1007
|
-
`Invalid time ago format: "${t}". Must be a number followed by a time unit. Valid units: s/sec/seconds (seconds), m/min/minutes (minutes), h/hours (hours), d/days (days), w/weeks (weeks), M/months (months), Y/years (years). Examples: "30s", "0.5h", "1.5d", "7d", "3w", "6M", "1Y". Format is case-insensitive except M (months) must be uppercase to distinguish from m (minutes).`
|
|
1008
|
-
);
|
|
1009
|
-
const s = parseFloat(r[1]);
|
|
1010
|
-
let o = r[2];
|
|
1011
|
-
switch (o !== "M" && (o = o.toLowerCase(), o.startsWith("month") ? o = "M" : o.length > 1 && (o = o[0])), o) {
|
|
1012
|
-
case "s":
|
|
1013
|
-
return s * 1e3;
|
|
1014
|
-
case "m":
|
|
1015
|
-
return s * 60 * 1e3;
|
|
1016
|
-
case "h":
|
|
1017
|
-
return s * 60 * 60 * 1e3;
|
|
1018
|
-
case "d":
|
|
1019
|
-
return s * 24 * 60 * 60 * 1e3;
|
|
1020
|
-
case "w":
|
|
1021
|
-
return s * 7 * 24 * 60 * 60 * 1e3;
|
|
1022
|
-
case "M":
|
|
1023
|
-
return s * 30 * 24 * 60 * 60 * 1e3;
|
|
1024
|
-
case "y":
|
|
1025
|
-
return s * 365 * 24 * 60 * 60 * 1e3;
|
|
1026
|
-
default:
|
|
1027
|
-
throw new Error(
|
|
1028
|
-
`Unknown time unit: "${o}". Valid time units are: s (seconds), m (minutes), h (hours), d (days), w (weeks), M (months), Y (years). Use uppercase M for months to distinguish from lowercase m for minutes. Examples: "30s", "5m", "2h", "7d", "3w", "6M", "1Y".`
|
|
1029
|
-
);
|
|
1030
|
-
}
|
|
1031
|
-
}
|
|
1032
|
-
function ge(t) {
|
|
1033
|
-
const r = t.match(/^\s*(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)\s*$/i);
|
|
1034
|
-
if (!r)
|
|
1035
|
-
throw new Error(
|
|
1036
|
-
`Invalid size format: "${t}". Must be a number (integer or decimal) followed by a size unit. Valid units: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary units (1024-based). Examples: "1B", "2.5KB", "100MB", "1.2GB", "0.5TB". Units are case-insensitive.`
|
|
1037
|
-
);
|
|
1038
|
-
const s = parseFloat(r[1]), o = r[2].toUpperCase();
|
|
1039
|
-
switch (o) {
|
|
1040
|
-
case "B":
|
|
1041
|
-
return s;
|
|
1042
|
-
case "KB":
|
|
1043
|
-
return s * 1024;
|
|
1044
|
-
case "MB":
|
|
1045
|
-
return s * 1024 * 1024;
|
|
1046
|
-
case "GB":
|
|
1047
|
-
return s * 1024 * 1024 * 1024;
|
|
1048
|
-
case "TB":
|
|
1049
|
-
return s * 1024 * 1024 * 1024 * 1024;
|
|
1050
|
-
default:
|
|
1051
|
-
throw new Error(
|
|
1052
|
-
`Unknown size unit: "${o}". Valid size units are: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary calculation (1KB = 1024 bytes). Examples: "500B", "2KB", "100MB", "1.5GB", "2TB". Units are case-insensitive.`
|
|
1053
|
-
);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
const Re = h.object({
|
|
1057
|
-
rootDir: h.string().optional().describe(
|
|
1058
|
-
'Root directory to list files from, resolved relative to the current working directory. Leave empty to use current directory. Examples: "src" (list src/ subdirectory), "../parent" (list parent directory), "docs/api" (list nested subdirectory). Path must exist and be accessible'
|
|
1059
|
-
),
|
|
1060
|
-
globs: h.array(h.string()).optional().describe(
|
|
1061
|
-
'Glob patterns to filter which files/directories to include. Add leading ** to match files and dirs in subdirectories. Examples: ["**/*.js"] (JavaScript files), ["src/**/*.ts"] (TypeScript files in src), ["**/dir/"] (all directories named "dir"), ["!node_modules"] (exclude {rootDir}/node_modules). If omitted, includes all files matching other criteria. Supports standard glob syntax: * (any chars), ** (any dirs), ? (single char), [abc] (char class)'
|
|
1062
|
-
),
|
|
1063
|
-
showFiles: h.boolean().optional().describe(
|
|
1064
|
-
"Whether to show regular files in the report table. Set to true to show files, false to hide them from the table. When both showFiles and showDirs are false, nothing will be shown in the table. It Does not affect totals. Default is false (do not show files in the table)"
|
|
1065
|
-
),
|
|
1066
|
-
showDirs: h.boolean().optional().describe(
|
|
1067
|
-
"Whether to show directories in the report table. Set to true to show directories, false to hide them from the table. When both showFiles and showDirs are false, nothing will be shown in the table. It Does not affect totals. Default is true (show directories in the table)"
|
|
1068
|
-
),
|
|
1069
|
-
sortBy: h.array(
|
|
1070
|
-
h.object({
|
|
1071
|
-
field: h.enum(["type", "path", "lastModified", "size", "totalCountFiles"]).describe(
|
|
1072
|
-
'Field to sort results by. "type" sorts files before directories. "path" sorts alphabetically by file/directory name. "lastModified" sorts by modification time (newest first when desc=true). "size" sorts by file/directory size (largest first when desc=true). "totalCountFiles" sorts by total files count (highest first when desc=true, directories only)'
|
|
1073
|
-
),
|
|
1074
|
-
desc: h.boolean().optional().describe("Sort in descending order (largest/newest first)")
|
|
1075
|
-
})
|
|
1076
|
-
).optional().describe(
|
|
1077
|
-
'Multi-level sorting configuration. Sorts are applied in array order - first sort is primary, second is secondary, etc. Example: [{field: "type", desc: false}, {field: "size", desc: true}] sorts by type ascending, then by size descending within each type'
|
|
1078
|
-
),
|
|
1079
|
-
fields: h.array(h.enum(["type", "path", "lastModified", "size", "totalCountFiles"])).optional().describe(
|
|
1080
|
-
'Which data fields to include in the formatted table output. "type" shows file/directory indicator. "path" shows relative file/directory path. "lastModified" shows last modification time as time-ago format (5m, 2h, 3d, etc). "size" shows file/directory size in human-readable format (KB, MB, GB). "totalCountFiles" shows total files count for directories (displays "-" for files). Adding lastModified, size, or totalCountFiles fields increases processing time. Do not set fields if you want to show only totals summary'
|
|
1081
|
-
),
|
|
1082
|
-
minTimeAgo: h.string().optional().describe(
|
|
1083
|
-
'Filter files/directories modified at least this long ago. Only items older than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: "1h" (modified more than 1 hour ago), "7d" (modified more than 7 days ago), "6M" (modified more than 6 months ago)'
|
|
1084
|
-
),
|
|
1085
|
-
maxTimeAgo: h.string().optional().describe(
|
|
1086
|
-
'Filter files/directories modified at most this long ago. Only items newer than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: "1h" (modified within last hour), "7d" (modified within last 7 days), "1M" (modified within last month). Combine with minTimeAgo for date ranges'
|
|
1087
|
-
),
|
|
1088
|
-
minTotalSize: h.string().optional().describe(
|
|
1089
|
-
'Filter files/directories with total size at least this large. Only items with size >= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: "1KB" (at least 1 kilobyte), "100MB" (at least 100 megabytes), "1.5GB" (at least 1.5 gigabytes)'
|
|
1090
|
-
),
|
|
1091
|
-
maxTotalSize: h.string().optional().describe(
|
|
1092
|
-
'Filter files/directories with total size at most this large. Only items with size <= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: "1MB" (up to 1 megabyte), "500KB" (up to 500 kilobytes), "10GB" (up to 10 gigabytes). Combine with minTotalSize for size ranges'
|
|
1093
|
-
)
|
|
1094
|
-
});
|
|
1095
|
-
async function Xt(t, r) {
|
|
1096
|
-
let s;
|
|
1097
|
-
try {
|
|
1098
|
-
s = Re.parse(t);
|
|
1099
|
-
} catch (p) {
|
|
1100
|
-
return {
|
|
1101
|
-
error: C(p)
|
|
1102
|
-
};
|
|
1103
|
-
}
|
|
1104
|
-
const {
|
|
1105
|
-
globs: o,
|
|
1106
|
-
showFiles: e,
|
|
1107
|
-
showDirs: n,
|
|
1108
|
-
sortBy: a,
|
|
1109
|
-
minTimeAgo: i,
|
|
1110
|
-
maxTimeAgo: u,
|
|
1111
|
-
minTotalSize: c,
|
|
1112
|
-
maxTotalSize: l
|
|
1113
|
-
} = s;
|
|
1114
|
-
if (s.fields && s.fields.length > 0 && !s.fields.includes("path"))
|
|
1115
|
-
return {
|
|
1116
|
-
error: 'Fields array must include "path" field when fields are specified. The "path" field is required to identify files and directories in the output'
|
|
1117
|
-
};
|
|
1118
|
-
const f = s.fields ? s.fields.map((p) => p === "totalCountFiles" ? "countFiles" : p === "lastModified" ? "dateModified" : p) : [];
|
|
1119
|
-
let d = a?.map((p) => {
|
|
1120
|
-
let y = p.field;
|
|
1121
|
-
return y === "totalCountFiles" && (y = "countFiles"), y === "lastModified" && (y = "dateModified"), {
|
|
1122
|
-
field: y,
|
|
1123
|
-
desc: p.desc ?? !1
|
|
1124
|
-
// Default to ascending if not specified
|
|
1125
|
-
};
|
|
1126
|
-
}) ?? null;
|
|
1127
|
-
(!d || d.length === 0) && (d = [{ field: "path", desc: !1 }]);
|
|
1128
|
-
const m = d?.map((p) => p.field) || [], g = T.resolve(
|
|
1129
|
-
r.workingDir || "",
|
|
1130
|
-
s.rootDir || ""
|
|
1131
|
-
);
|
|
1132
|
-
try {
|
|
1133
|
-
try {
|
|
1134
|
-
await B.promises.access(g, B.constants.F_OK);
|
|
1135
|
-
} catch ($) {
|
|
1136
|
-
if ($.code === "ENOENT")
|
|
1137
|
-
return {
|
|
1138
|
-
error: `Directory does not exist: "${g}". Verify the path is correct and accessible. If using rootDir parameter, ensure it exists relative to the current working directory. Use fs-list without rootDir to list the current directory, or check parent directories first.`
|
|
1139
|
-
};
|
|
1140
|
-
throw $;
|
|
1141
|
-
}
|
|
1142
|
-
const p = o && o.length > 0 ? o.map(($) => ({
|
|
1143
|
-
value: $,
|
|
1144
|
-
valueType: "pattern",
|
|
1145
|
-
exclude: !1
|
|
1146
|
-
})) : [{ value: "**", valueType: "pattern", exclude: !1 }], y = r.globsExclude || [], w = [...p, ...y], S = {
|
|
1147
|
-
files: e ?? !1,
|
|
1148
|
-
dirs: n ?? !1,
|
|
1149
|
-
dateModified: f.includes("dateModified") || m.includes("dateModified"),
|
|
1150
|
-
size: f.includes("size") || m.includes("size"),
|
|
1151
|
-
countFiles: f.includes("countFiles") || m.includes("countFiles")
|
|
1152
|
-
};
|
|
1153
|
-
let M = null, I = null;
|
|
1154
|
-
if (i || u)
|
|
1155
|
-
try {
|
|
1156
|
-
const $ = Date.now(), v = u ? $ - pe(u) : null, E = i ? $ - pe(i) : null;
|
|
1157
|
-
M = [v, E];
|
|
1158
|
-
} catch ($) {
|
|
1159
|
-
return {
|
|
1160
|
-
error: $ instanceof Error ? $.message : "Unknown error parsing time ago filter"
|
|
1161
|
-
};
|
|
1162
|
-
}
|
|
1163
|
-
if (c || l)
|
|
1164
|
-
try {
|
|
1165
|
-
const $ = c ? ge(c) : null, v = l ? ge(l) : null;
|
|
1166
|
-
I = [$, v];
|
|
1167
|
-
} catch ($) {
|
|
1168
|
-
return {
|
|
1169
|
-
error: $ instanceof Error ? $.message : "Unknown error parsing size filter"
|
|
1170
|
-
};
|
|
1171
|
-
}
|
|
1172
|
-
const b = await Qt({
|
|
1173
|
-
rootDir: g || null,
|
|
1174
|
-
globs: w,
|
|
1175
|
-
result: S,
|
|
1176
|
-
dateModified: M,
|
|
1177
|
-
totalSize: I
|
|
1178
|
-
});
|
|
1179
|
-
return b.items.length > he ? {
|
|
1180
|
-
error: `Number of paths (${b.items.length}) exceeds maximum allowed (${he}). Consider using more specific glob patterns or filters to reduce the result set.`
|
|
1181
|
-
} : {
|
|
1182
|
-
output: Yt(b, {
|
|
1183
|
-
sort: d,
|
|
1184
|
-
fields: f,
|
|
1185
|
-
totals: !0
|
|
1186
|
-
})
|
|
1187
|
-
};
|
|
1188
|
-
} catch (p) {
|
|
1189
|
-
return { error: p instanceof Error ? p.message : "Unknown error" };
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
function er(t, r) {
|
|
1193
|
-
t(
|
|
1194
|
-
"fs-list",
|
|
1195
|
-
{
|
|
1196
|
-
title: "List Files and Directories",
|
|
1197
|
-
description: "List files and directories with advanced filtering, sorting and formatting options. Use this to analyze filesystem structure",
|
|
1198
|
-
inputSchema: Re.shape
|
|
1199
|
-
},
|
|
1200
|
-
async (s) => {
|
|
1201
|
-
const o = await Xt(s, r);
|
|
1202
|
-
return o.error ? `Method: fs-list(${JSON.stringify(s)})
|
|
1203
|
-
❌ Error: ${o.error}` : `Method: fs-list(${JSON.stringify(s)})
|
|
1204
|
-
${o.output || JSON.stringify(o, null, 2)}`;
|
|
1205
|
-
}
|
|
1206
|
-
);
|
|
1207
|
-
}
|
|
1208
|
-
const _ = /* @__PURE__ */ new Map();
|
|
1209
|
-
function V(t) {
|
|
1210
|
-
return _.has(t) || _.set(t, {
|
|
1211
|
-
fsSnapshotQueries: /* @__PURE__ */ new Map(),
|
|
1212
|
-
fsSnapshots: /* @__PURE__ */ new Map()
|
|
1213
|
-
}), _.get(t);
|
|
1214
|
-
}
|
|
1215
|
-
function we(t) {
|
|
1216
|
-
const r = t.match(
|
|
1217
|
-
/^\s*(\d+(?:\.\d+)?)\s*([smhdwMY]|sec(onds?)?|min(utes?)?|hours?|days?|weeks?|months?|years?)\s*$/i
|
|
1218
|
-
);
|
|
1219
|
-
if (!r)
|
|
1220
|
-
throw new Error(
|
|
1221
|
-
`Invalid time ago format: "${t}". Must be a number followed by a time unit. Valid units: s/sec/seconds (seconds), m/min/minutes (minutes), h/hours (hours), d/days (days), w/weeks (weeks), M/months (months), Y/years (years). Examples: "30s", "0.5h", "1.5d", "7d", "3w", "6M", "1Y". Format is case-insensitive except M (months) must be uppercase to distinguish from m (minutes).`
|
|
1222
|
-
);
|
|
1223
|
-
const s = parseFloat(r[1]);
|
|
1224
|
-
let o = r[2];
|
|
1225
|
-
switch (o !== "M" && (o = o.toLowerCase(), o.startsWith("month") ? o = "M" : o.length > 1 && (o = o[0])), o) {
|
|
1226
|
-
case "s":
|
|
1227
|
-
return s * 1e3;
|
|
1228
|
-
case "m":
|
|
1229
|
-
return s * 60 * 1e3;
|
|
1230
|
-
case "h":
|
|
1231
|
-
return s * 60 * 60 * 1e3;
|
|
1232
|
-
case "d":
|
|
1233
|
-
return s * 24 * 60 * 60 * 1e3;
|
|
1234
|
-
case "w":
|
|
1235
|
-
return s * 7 * 24 * 60 * 60 * 1e3;
|
|
1236
|
-
case "M":
|
|
1237
|
-
return s * 30 * 24 * 60 * 60 * 1e3;
|
|
1238
|
-
case "y":
|
|
1239
|
-
return s * 365 * 24 * 60 * 60 * 1e3;
|
|
1240
|
-
default:
|
|
1241
|
-
throw new Error(
|
|
1242
|
-
`Unknown time unit: "${o}". Valid time units are: s (seconds), m (minutes), h (hours), d (days), w (weeks), M (months), Y (years). Use uppercase M for months to distinguish from lowercase m for minutes. Examples: "30s", "5m", "2h", "7d", "3w", "6M", "1Y".`
|
|
1243
|
-
);
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
|
-
function ye(t) {
|
|
1247
|
-
const r = t.match(/^\s*(\d+(?:\.\d+)?)\s*(B|KB|MB|GB|TB)\s*$/i);
|
|
1248
|
-
if (!r)
|
|
1249
|
-
throw new Error(
|
|
1250
|
-
`Invalid size format: "${t}". Must be a number (integer or decimal) followed by a size unit. Valid units: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary units (1024-based). Examples: "1B", "2.5KB", "100MB", "1.2GB", "0.5TB". Units are case-insensitive.`
|
|
1251
|
-
);
|
|
1252
|
-
const s = parseFloat(r[1]), o = r[2].toUpperCase();
|
|
1253
|
-
switch (o) {
|
|
1254
|
-
case "B":
|
|
1255
|
-
return s;
|
|
1256
|
-
case "KB":
|
|
1257
|
-
return s * 1024;
|
|
1258
|
-
case "MB":
|
|
1259
|
-
return s * 1024 * 1024;
|
|
1260
|
-
case "GB":
|
|
1261
|
-
return s * 1024 * 1024 * 1024;
|
|
1262
|
-
case "TB":
|
|
1263
|
-
return s * 1024 * 1024 * 1024 * 1024;
|
|
1264
|
-
default:
|
|
1265
|
-
throw new Error(
|
|
1266
|
-
`Unknown size unit: "${o}". Valid size units are: B (bytes), KB (kilobytes), MB (megabytes), GB (gigabytes), TB (terabytes). Uses binary calculation (1KB = 1024 bytes). Examples: "500B", "2KB", "100MB", "1.5GB", "2TB". Units are case-insensitive.`
|
|
1267
|
-
);
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
const Z = h.object({
|
|
1271
|
-
name: h.string().describe(
|
|
1272
|
-
"Unique name for the filesystem snapshot query. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
1273
|
-
),
|
|
1274
|
-
rootDir: h.string().optional().describe(
|
|
1275
|
-
'Root directory to snapshot, resolved relative to the current working directory. Leave empty to use current directory. Examples: "src" (snapshot src/ subdirectory), "../parent" (snapshot parent directory), "docs/api" (snapshot nested subdirectory). Path must exist and be accessible'
|
|
1276
|
-
),
|
|
1277
|
-
globs: h.array(h.string()).optional().describe(
|
|
1278
|
-
'Glob patterns to filter which files/directories to include in snapshot. Add leading ** to match files and dirs in subdirectories. Examples: ["**/*.js"] (JavaScript files), ["src/**/*.ts"] (TypeScript files in src), ["**/dir/"] (all directories named "dir"), ["!node_modules"] (exclude {rootDir}/node_modules). If omitted, includes all files matching other criteria. Supports standard glob syntax: * (any chars), ** (any dirs), ? (single char), [abc] (char class)'
|
|
1279
|
-
),
|
|
1280
|
-
types: h.array(h.enum(["file", "dir"])).optional().describe(
|
|
1281
|
-
"Types of items to include in the snapshot. If omitted, includes both files and directories"
|
|
1282
|
-
),
|
|
1283
|
-
extraFields: h.array(h.enum(["lastModified", "size", "countMatched"])).optional().describe(
|
|
1284
|
-
'Which extra data fields to include in the snapshot tree output. "lastModified" shows last modification time as time-ago format (5m, 2h, 3d, etc). "size" shows file/directory size in human-readable format (KB, MB, GB). "countMatched" shows total matched items count'
|
|
1285
|
-
),
|
|
1286
|
-
minTimeAgo: h.string().optional().describe(
|
|
1287
|
-
'Filter files/directories modified at least this long ago. Only items older than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: "1h" (modified more than 1 hour ago), "7d" (modified more than 7 days ago), "6M" (modified more than 6 months ago)'
|
|
1288
|
-
),
|
|
1289
|
-
maxTimeAgo: h.string().optional().describe(
|
|
1290
|
-
'Filter files/directories modified at most this long ago. Only items newer than this duration will be included. Format: number + unit (s/m/h/d/w/M/Y). Examples: "1h" (modified within last hour), "7d" (modified within last 7 days), "1M" (modified within last month). Combine with minTimeAgo for date ranges'
|
|
1291
|
-
),
|
|
1292
|
-
minTotalSize: h.string().optional().describe(
|
|
1293
|
-
'Filter files/directories with total size at least this large. Only items with size >= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: "1KB" (at least 1 kilobyte), "100MB" (at least 100 megabytes), "1.5GB" (at least 1.5 gigabytes)'
|
|
1294
|
-
),
|
|
1295
|
-
maxTotalSize: h.string().optional().describe(
|
|
1296
|
-
'Filter files/directories with total size at most this large. Only items with size <= this value will be included. For directories, uses total size of all contents. Format: number + unit (B/KB/MB/GB/TB). Examples: "1MB" (up to 1 megabyte), "500KB" (up to 500 kilobytes), "10GB" (up to 10 gigabytes). Combine with minTotalSize for size ranges'
|
|
1297
|
-
)
|
|
1298
|
-
}), be = new Map(
|
|
1299
|
-
[
|
|
1300
|
-
"name",
|
|
1301
|
-
"type",
|
|
1302
|
-
"countMatched",
|
|
1303
|
-
"size",
|
|
1304
|
-
"dateModified"
|
|
1305
|
-
].map((t, r) => [t, r])
|
|
1306
|
-
);
|
|
1307
|
-
function tr(t, r) {
|
|
1308
|
-
const s = be.get(t) ?? 1 / 0, o = be.get(r) ?? 1 / 0;
|
|
1309
|
-
return s > o ? 1 : s < o ? -1 : 0;
|
|
1310
|
-
}
|
|
1311
|
-
async function Pe(t, r, s) {
|
|
1312
|
-
let o;
|
|
1313
|
-
try {
|
|
1314
|
-
o = Z.parse(t);
|
|
1315
|
-
} catch (m) {
|
|
1316
|
-
return {
|
|
1317
|
-
error: C(m)
|
|
1318
|
-
};
|
|
1319
|
-
}
|
|
1320
|
-
const {
|
|
1321
|
-
name: e,
|
|
1322
|
-
globs: n,
|
|
1323
|
-
types: a,
|
|
1324
|
-
minTimeAgo: i,
|
|
1325
|
-
maxTimeAgo: u,
|
|
1326
|
-
minTotalSize: c,
|
|
1327
|
-
maxTotalSize: l
|
|
1328
|
-
} = o;
|
|
1329
|
-
if (!s.sessionId)
|
|
1330
|
-
return {
|
|
1331
|
-
error: "Session ID is required"
|
|
1332
|
-
};
|
|
1333
|
-
const f = V(s.sessionId);
|
|
1334
|
-
if (f.fsSnapshotQueries.has(e))
|
|
1335
|
-
return {
|
|
1336
|
-
error: `Filesystem snapshot query "${e}" already exists`
|
|
1337
|
-
};
|
|
1338
|
-
const d = T.resolve(r.workingDir || "", o.rootDir || "").replace(/\\/g, "/");
|
|
1339
|
-
try {
|
|
1340
|
-
try {
|
|
1341
|
-
await B.promises.access(d, B.constants.F_OK);
|
|
1342
|
-
} catch (x) {
|
|
1343
|
-
if (x.code === "ENOENT")
|
|
1344
|
-
return {
|
|
1345
|
-
error: `Directory does not exist: "${d}". Verify the path is correct and accessible. If using rootDir parameter, ensure it exists relative to the current working directory. Use fs-snapshot-query-create without rootDir to snapshot the current directory, or check parent directories first.`
|
|
1346
|
-
};
|
|
1347
|
-
throw x;
|
|
1348
|
-
}
|
|
1349
|
-
const m = o.extraFields ? o.extraFields.map((x) => x === "lastModified" ? "dateModified" : x) : [];
|
|
1350
|
-
m.includes("name") || m.push("name"), m.sort(tr);
|
|
1351
|
-
const g = n && n.length > 0 ? n.map((x) => ({
|
|
1352
|
-
value: x,
|
|
1353
|
-
valueType: "pattern",
|
|
1354
|
-
exclude: !1
|
|
1355
|
-
})) : [{ value: "**", valueType: "pattern", exclude: !1 }], p = r.globsExclude || [], y = [...g, ...p];
|
|
1356
|
-
let w = null, S = null;
|
|
1357
|
-
if (i || u)
|
|
1358
|
-
try {
|
|
1359
|
-
const x = Date.now(), $ = u ? x - we(u) : null, v = i ? x - we(i) : null;
|
|
1360
|
-
w = [$, v];
|
|
1361
|
-
} catch (x) {
|
|
1362
|
-
return {
|
|
1363
|
-
error: x instanceof Error ? x.message : "Unknown error parsing time ago filter"
|
|
1364
|
-
};
|
|
1365
|
-
}
|
|
1366
|
-
if (c || l)
|
|
1367
|
-
try {
|
|
1368
|
-
const x = c ? ye(c) : null, $ = l ? ye(l) : null;
|
|
1369
|
-
S = [x, $];
|
|
1370
|
-
} catch (x) {
|
|
1371
|
-
return {
|
|
1372
|
-
error: x instanceof Error ? x.message : "Unknown error parsing size filter"
|
|
1373
|
-
};
|
|
1374
|
-
}
|
|
1375
|
-
const M = a ? a.includes("file") : !0, I = a ? a.includes("dir") : !0, b = {
|
|
1376
|
-
name: e,
|
|
1377
|
-
rootDir: d,
|
|
1378
|
-
globs: y,
|
|
1379
|
-
matchFiles: M,
|
|
1380
|
-
matchDirs: I,
|
|
1381
|
-
dateModified: w,
|
|
1382
|
-
totalSize: S,
|
|
1383
|
-
fields: m
|
|
1384
|
-
};
|
|
1385
|
-
return f.fsSnapshotQueries.set(e, b), {
|
|
1386
|
-
snapshotQuery: b
|
|
1387
|
-
};
|
|
1388
|
-
} catch (m) {
|
|
1389
|
-
return {
|
|
1390
|
-
error: m instanceof Error ? m.message : "Unknown error"
|
|
1391
|
-
};
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
function rr(t, r) {
|
|
1395
|
-
t(
|
|
1396
|
-
"fs-snapshot-query-create",
|
|
1397
|
-
{
|
|
1398
|
-
title: "Create Filesystem Snapshot Query",
|
|
1399
|
-
description: "Create a filesystem snapshot query. Prefer fs-snapshot-browse if you need to immediately create a query, snapshot and browse it",
|
|
1400
|
-
inputSchema: Z.shape
|
|
1401
|
-
},
|
|
1402
|
-
async (s, o) => {
|
|
1403
|
-
const e = await Pe(s, r, o);
|
|
1404
|
-
return e.error != null ? `Method: fs-snapshot-query-create(${JSON.stringify(s)})
|
|
1405
|
-
❌ Error: ${e.error}` : `Method: fs-snapshot-query-create(${JSON.stringify(s)})
|
|
1406
|
-
✅ Filesystem snapshot query "${e.snapshotQuery.name}" created successfully`;
|
|
1407
|
-
}
|
|
1408
|
-
);
|
|
1409
|
-
}
|
|
1410
|
-
function j(t) {
|
|
1411
|
-
const { idToNode: r, idToChildIds: s } = t, o = r.get(null);
|
|
1412
|
-
if (o == null)
|
|
1413
|
-
throw new Error(
|
|
1414
|
-
"Impossible behavior: root node (id: null) not found in idToNode"
|
|
1415
|
-
);
|
|
1416
|
-
const e = /* @__PURE__ */ new Map();
|
|
1417
|
-
return r.forEach((n, a) => {
|
|
1418
|
-
if (n != null) {
|
|
1419
|
-
if (e.has(n)) {
|
|
1420
|
-
const i = e.get(n);
|
|
1421
|
-
throw new Error(
|
|
1422
|
-
`Impossible behavior: node appears with multiple IDs (existing: ${i}, new: ${a})`
|
|
1423
|
-
);
|
|
1424
|
-
}
|
|
1425
|
-
e.set(n, a);
|
|
1426
|
-
}
|
|
1427
|
-
}), {
|
|
1428
|
-
root: o,
|
|
1429
|
-
getNode: (n) => r.get(n) ?? null,
|
|
1430
|
-
getId: (n) => e.get(n) ?? null,
|
|
1431
|
-
getChilds: (n) => {
|
|
1432
|
-
let a = e.get(n);
|
|
1433
|
-
if (a == null)
|
|
1434
|
-
if (n === r.get(null))
|
|
1435
|
-
a = null;
|
|
1436
|
-
else
|
|
1437
|
-
throw new Error("Impossible behavior: node not found in idToNode");
|
|
1438
|
-
const i = s.get(a);
|
|
1439
|
-
return i == null ? null : i.map((u) => {
|
|
1440
|
-
const c = r.get(u);
|
|
1441
|
-
if (c == null)
|
|
1442
|
-
throw new Error(
|
|
1443
|
-
`Child node with id '${u}' not found in idToNode`
|
|
1444
|
-
);
|
|
1445
|
-
return c;
|
|
1446
|
-
});
|
|
1447
|
-
}
|
|
1448
|
-
};
|
|
1449
|
-
}
|
|
1450
|
-
function ze(t, r, s) {
|
|
1451
|
-
let o = null;
|
|
1452
|
-
for (let e = 0, n = r.length; e < n; e++) {
|
|
1453
|
-
const a = r[e], i = t(a), u = i == null ? null : ze(t, i, s), c = s(a, u);
|
|
1454
|
-
c != null && (o == null && (o = []), o.push(c));
|
|
1455
|
-
}
|
|
1456
|
-
return o;
|
|
1457
|
-
}
|
|
1458
|
-
function Le(t) {
|
|
1459
|
-
const { getId: r, getChilds: s, rootNodes: o, createSnapshotNode: e } = t, n = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map(), u = ze(
|
|
1460
|
-
s,
|
|
1461
|
-
o,
|
|
1462
|
-
(l, f) => {
|
|
1463
|
-
const d = e(l, f);
|
|
1464
|
-
if (l != null && d != null) {
|
|
1465
|
-
const m = r(l);
|
|
1466
|
-
n.set(m, d), a.set(d, m);
|
|
1467
|
-
}
|
|
1468
|
-
return d != null && f != null && i.set(
|
|
1469
|
-
a.get(d),
|
|
1470
|
-
f.map((m) => a.get(m))
|
|
1471
|
-
), d;
|
|
1472
|
-
}
|
|
1473
|
-
), c = e(null, u);
|
|
1474
|
-
if (c == null)
|
|
1475
|
-
throw new Error("Impossible behavior: rootNode == null");
|
|
1476
|
-
return n.set(null, c), u != null && i.set(
|
|
1477
|
-
null,
|
|
1478
|
-
u.map((l) => a.get(l))
|
|
1479
|
-
), {
|
|
1480
|
-
idToNode: n,
|
|
1481
|
-
idToChildIds: i
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
|
-
function W(t) {
|
|
1485
|
-
return t = t?.replace(/\\/g, "/").replace(/\/$/, ""), !t || t === "." ? null : t;
|
|
1486
|
-
}
|
|
1487
|
-
async function sr(t) {
|
|
1488
|
-
const r = /* @__PURE__ */ new Map(), s = /* @__PURE__ */ new Map(), o = T.resolve(t.rootDir || "."), n = {
|
|
1489
|
-
path: ".",
|
|
1490
|
-
name: T.basename(o),
|
|
1491
|
-
type: "dir",
|
|
1492
|
-
isMatched: !1,
|
|
1493
|
-
dateModified: null,
|
|
1494
|
-
size: 0
|
|
1495
|
-
};
|
|
1496
|
-
r.set(null, n);
|
|
1497
|
-
const a = await Be({
|
|
1498
|
-
rootDir: o,
|
|
1499
|
-
globs: t.globs
|
|
1500
|
-
});
|
|
1501
|
-
return await Fe({
|
|
1502
|
-
paths: [o],
|
|
1503
|
-
walkLinks: !0,
|
|
1504
|
-
matchPath: Oe({
|
|
1505
|
-
globs: a,
|
|
1506
|
-
rootDir: o,
|
|
1507
|
-
noCase: !0
|
|
1508
|
-
}),
|
|
1509
|
-
handlePath: async ({ path: i, stat: u, itemStat: c }) => {
|
|
1510
|
-
const l = T.relative(o, i), f = u.isDirectory(), d = u.isFile();
|
|
1511
|
-
if (!f && !d)
|
|
1512
|
-
return !0;
|
|
1513
|
-
const m = W(l || "."), g = f ? "dir" : "file", p = f ? null : u.mtimeMs, y = u.size;
|
|
1514
|
-
let w = !0;
|
|
1515
|
-
if (d && !t.matchFiles && (w = !1), f && !t.matchDirs && (w = !1), w && d && t.dateModified && p != null) {
|
|
1516
|
-
const [b, x] = t.dateModified;
|
|
1517
|
-
(b != null && p < b || x != null && p > x) && (w = !1);
|
|
1518
|
-
}
|
|
1519
|
-
if (w && d && t.totalSize && y != null) {
|
|
1520
|
-
const [b, x] = t.totalSize;
|
|
1521
|
-
(b != null && y < b || x != null && y > x) && (w = !1);
|
|
1522
|
-
}
|
|
1523
|
-
if (f && !w) {
|
|
1524
|
-
if (!(c.countFiles && c.countFiles > 0)) return !1;
|
|
1525
|
-
} else if (!w)
|
|
1526
|
-
return !1;
|
|
1527
|
-
const S = {
|
|
1528
|
-
path: m ?? ".",
|
|
1529
|
-
name: T.basename(i),
|
|
1530
|
-
type: g,
|
|
1531
|
-
dateModified: p,
|
|
1532
|
-
size: y,
|
|
1533
|
-
isMatched: w
|
|
1534
|
-
};
|
|
1535
|
-
if (m == null)
|
|
1536
|
-
return n.dateModified = p, n.size = y, n.isMatched = w, !0;
|
|
1537
|
-
r.set(m, S);
|
|
1538
|
-
const M = W(T.dirname(m).replace(/\\/g, "/"));
|
|
1539
|
-
let I = s.get(M);
|
|
1540
|
-
return I || (I = [], s.set(M, I)), I.push(m), !0;
|
|
1541
|
-
}
|
|
1542
|
-
}), {
|
|
1543
|
-
idToNode: r,
|
|
1544
|
-
idToChildIds: s
|
|
1545
|
-
};
|
|
1546
|
-
}
|
|
1547
|
-
const or = [
|
|
1548
|
-
{ name: "[ ]", match: (t) => t === 32, min: 2, max: 81 },
|
|
1549
|
-
{ name: "[\\t]", match: (t) => t === 9, min: 2, max: 20 },
|
|
1550
|
-
{ name: "[\\n]", match: (t) => t === 10, min: 2, max: 14 },
|
|
1551
|
-
{ name: "[-]", match: (t) => t === 45, min: 2, max: 16 },
|
|
1552
|
-
{ name: "[=]", match: (t) => t === 61, min: 2, max: 16 },
|
|
1553
|
-
{ name: "[_]", match: (t) => t === 95, min: 2, max: 16 },
|
|
1554
|
-
{ name: "[*]", match: (t) => t === 42, min: 2, max: 16 },
|
|
1555
|
-
{ name: "[.]", match: (t) => t === 46, min: 2, max: 16 },
|
|
1556
|
-
{ name: "[0-9]", match: (t) => t >= 48 && t <= 57, min: 2, max: 3 }
|
|
1557
|
-
// { name: '[a-z]', match: c => c >= 97 && c <= 122, min: 2, max: 2 },
|
|
1558
|
-
// { name: '[A-Z]', match: c => c >= 65 && c <= 90, min: 2, max: 2 },
|
|
1559
|
-
// Other ASCII symbols
|
|
1560
|
-
// {
|
|
1561
|
-
// name: 'Other ASCII',
|
|
1562
|
-
// match: c =>
|
|
1563
|
-
// (c > 32 && c < 48) ||
|
|
1564
|
-
// (c > 57 && c < 65) ||
|
|
1565
|
-
// (c > 90 && c < 97),
|
|
1566
|
-
// min: 2,
|
|
1567
|
-
// max: 2,
|
|
1568
|
-
// },
|
|
1569
|
-
];
|
|
1570
|
-
function Se(t, r = or) {
|
|
1571
|
-
const s = t.length;
|
|
1572
|
-
if (s === 0) return 0;
|
|
1573
|
-
const o = r.length;
|
|
1574
|
-
if (o === 0)
|
|
1575
|
-
return s;
|
|
1576
|
-
let e = 0, n = 0;
|
|
1577
|
-
for (; n < s; ) {
|
|
1578
|
-
const a = t.charCodeAt(n);
|
|
1579
|
-
let i = !1;
|
|
1580
|
-
for (let u = 0; u < o; u++) {
|
|
1581
|
-
const c = r[u];
|
|
1582
|
-
if (c.match(a)) {
|
|
1583
|
-
let l = 1;
|
|
1584
|
-
for (; ++n < s && c.match(t.charCodeAt(n)) && l < c.max; )
|
|
1585
|
-
l++;
|
|
1586
|
-
if (l >= c.min) {
|
|
1587
|
-
e++, i = !0;
|
|
1588
|
-
break;
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
i || (n++, e++);
|
|
1593
|
-
}
|
|
1594
|
-
return e;
|
|
1595
|
-
}
|
|
1596
|
-
function Ue(t) {
|
|
1597
|
-
let r = 0;
|
|
1598
|
-
return r += Se(t.textOpen) + 1, t.textClose != null && (r += Se(t.textClose) + 1), t.indent && (r += 1), r;
|
|
1599
|
-
}
|
|
1600
|
-
const xe = ["B", "KB", "MB", "GB", "TB"], $e = 1024;
|
|
1601
|
-
function nr(t) {
|
|
1602
|
-
if (t == null) return "-";
|
|
1603
|
-
let r = t ?? 0, s = 0;
|
|
1604
|
-
for (; r >= $e && s < xe.length - 1; )
|
|
1605
|
-
r /= $e, s++;
|
|
1606
|
-
return `${s === 0 ? r.toString() : r.toFixed(2)}${xe[s]}`;
|
|
1607
|
-
}
|
|
1608
|
-
function ir(t) {
|
|
1609
|
-
const s = Date.now() - t;
|
|
1610
|
-
if (s < 0) return "0s";
|
|
1611
|
-
const o = Math.floor(s / 1e3), e = Math.floor(o / 60), n = Math.floor(e / 60), a = Math.floor(n / 24), i = Math.floor(a / 7), u = Math.floor(a / 30), c = Math.floor(a / 365);
|
|
1612
|
-
return c > 0 ? `${c}Y` : u > 0 ? `${u}M` : i > 0 ? `${i}w` : a > 0 ? `${a}d` : n > 0 ? `${n}h` : e > 0 ? `${e}m` : `${o}s`;
|
|
1613
|
-
}
|
|
1614
|
-
function ar(t) {
|
|
1615
|
-
return function(s, o) {
|
|
1616
|
-
const e = t.get(s), n = t.get(o);
|
|
1617
|
-
if (e.type !== n.type)
|
|
1618
|
-
return e.type === "file" ? -1 : 1;
|
|
1619
|
-
if (e.type === "file")
|
|
1620
|
-
return e.name < n.name ? -1 : e.name > n.name ? 1 : 0;
|
|
1621
|
-
{
|
|
1622
|
-
const a = e.countFiles || 0, i = n.countFiles || 0;
|
|
1623
|
-
return a < i ? -1 : a > i ? 1 : e.name < n.name ? -1 : e.name > n.name ? 1 : 0;
|
|
1624
|
-
}
|
|
1625
|
-
};
|
|
1626
|
-
}
|
|
1627
|
-
function cr(t) {
|
|
1628
|
-
const r = t.fields ?? [];
|
|
1629
|
-
return function(o, e) {
|
|
1630
|
-
let n = "", a, i = 0;
|
|
1631
|
-
const u = e ? e.length : 0;
|
|
1632
|
-
let c = 1, l, f = 0, d = 0, m = 0, g = 0, p = null, y, w, S;
|
|
1633
|
-
if (e)
|
|
1634
|
-
for (let I = 0; I < e.length; I++) {
|
|
1635
|
-
const b = e[I];
|
|
1636
|
-
i += b.countMatched, c += b.countTotal, f += b.tokens, d += b.tokensTotal, m += b.size, g += b.countFiles, b.dateModified != null && (p == null || b.dateModified > p) && (p = b.dateModified);
|
|
1637
|
-
}
|
|
1638
|
-
o ? (y = o.type, w = o.name, S = o.path, a = o.isMatched, a && (i += 1), o.type === "file" ? (m = o.size || 0, g = 1, p = o.dateModified || null) : o.dateModified != null && (p == null || o.dateModified > p) && (p = o.dateModified)) : (y = "dir", w = "<root>", S = ".", a = !0);
|
|
1639
|
-
for (let I = 0, b = r.length; I < b; I++) {
|
|
1640
|
-
const x = r[I];
|
|
1641
|
-
switch (I > 0 && (n += " "), x) {
|
|
1642
|
-
case "dateModified":
|
|
1643
|
-
n += p ? ir(p) : "-";
|
|
1644
|
-
break;
|
|
1645
|
-
case "size":
|
|
1646
|
-
n += nr(m);
|
|
1647
|
-
break;
|
|
1648
|
-
case "type":
|
|
1649
|
-
n += y;
|
|
1650
|
-
break;
|
|
1651
|
-
case "name":
|
|
1652
|
-
n += y === "dir" ? `${w}/` : w;
|
|
1653
|
-
break;
|
|
1654
|
-
case "countMatched":
|
|
1655
|
-
n += i.toString();
|
|
1656
|
-
break;
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
const M = {
|
|
1660
|
-
indent: !0,
|
|
1661
|
-
textOpen: n,
|
|
1662
|
-
textClose: null
|
|
1663
|
-
};
|
|
1664
|
-
return l = Ue(M), d += l, {
|
|
1665
|
-
type: y,
|
|
1666
|
-
name: w,
|
|
1667
|
-
path: S,
|
|
1668
|
-
isMatched: a,
|
|
1669
|
-
countMatched: i,
|
|
1670
|
-
countChilds: u,
|
|
1671
|
-
countTotal: c,
|
|
1672
|
-
tokens: l,
|
|
1673
|
-
tokensChilds: f,
|
|
1674
|
-
tokensTotal: d,
|
|
1675
|
-
text: M,
|
|
1676
|
-
size: m,
|
|
1677
|
-
countFiles: g,
|
|
1678
|
-
dateModified: p
|
|
1679
|
-
};
|
|
1680
|
-
};
|
|
1681
|
-
}
|
|
1682
|
-
async function lr(t) {
|
|
1683
|
-
const r = await sr(t), s = j(r), o = s.getChilds(s.root), e = Le({
|
|
1684
|
-
getId: (a) => {
|
|
1685
|
-
const i = s.getId(a);
|
|
1686
|
-
if (i == null)
|
|
1687
|
-
throw new Error(
|
|
1688
|
-
`Invalid tree structure: node ID is null for node ${JSON.stringify(a)}`
|
|
1689
|
-
);
|
|
1690
|
-
return i;
|
|
1691
|
-
},
|
|
1692
|
-
getChilds: (a) => s.getChilds(a),
|
|
1693
|
-
createSnapshotNode: cr(t),
|
|
1694
|
-
rootNodes: o ?? []
|
|
1695
|
-
}), n = ar(e.idToNode);
|
|
1696
|
-
return e.idToChildIds.forEach((a) => {
|
|
1697
|
-
a.sort(n);
|
|
1698
|
-
}), j(e);
|
|
1699
|
-
}
|
|
1700
|
-
const X = h.object({
|
|
1701
|
-
queryName: h.string().optional().describe("Name of previously created filesystem snapshot query, to use"),
|
|
1702
|
-
query: Z.optional().describe(
|
|
1703
|
-
"Filesystem snapshot query creation options JSON to automatically create query"
|
|
1704
|
-
),
|
|
1705
|
-
name: h.string().describe(
|
|
1706
|
-
"Unique name for the filesystem snapshot. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
1707
|
-
)
|
|
1708
|
-
});
|
|
1709
|
-
async function Ae(t, r, s) {
|
|
1710
|
-
let o;
|
|
1711
|
-
try {
|
|
1712
|
-
o = X.parse(t);
|
|
1713
|
-
} catch (l) {
|
|
1714
|
-
return {
|
|
1715
|
-
error: C(l)
|
|
1716
|
-
};
|
|
1717
|
-
}
|
|
1718
|
-
const { name: e, queryName: n, query: a } = o;
|
|
1719
|
-
if (!s.sessionId)
|
|
1720
|
-
return {
|
|
1721
|
-
error: "Session ID is required"
|
|
1722
|
-
};
|
|
1723
|
-
const i = V(s.sessionId);
|
|
1724
|
-
if (i.fsSnapshots.has(e))
|
|
1725
|
-
return {
|
|
1726
|
-
error: `Filesystem snapshot "${e}" already exists`
|
|
1727
|
-
};
|
|
1728
|
-
if (n && a)
|
|
1729
|
-
return {
|
|
1730
|
-
error: "Either queryName or query must be provided, not both"
|
|
1731
|
-
};
|
|
1732
|
-
let u, c = !1;
|
|
1733
|
-
if (n) {
|
|
1734
|
-
const l = i.fsSnapshotQueries.get(n);
|
|
1735
|
-
if (!l)
|
|
1736
|
-
return {
|
|
1737
|
-
error: `Filesystem snapshot query "${n}" not found`
|
|
1738
|
-
};
|
|
1739
|
-
u = l;
|
|
1740
|
-
} else if (a) {
|
|
1741
|
-
const l = await Pe(
|
|
1742
|
-
a,
|
|
1743
|
-
r,
|
|
1744
|
-
s
|
|
1745
|
-
);
|
|
1746
|
-
if (l.error != null)
|
|
1747
|
-
return {
|
|
1748
|
-
error: l.error
|
|
1749
|
-
};
|
|
1750
|
-
u = l.snapshotQuery, c = !0;
|
|
1751
|
-
} else
|
|
1752
|
-
return {
|
|
1753
|
-
error: "Either queryName or query must be provided"
|
|
1754
|
-
};
|
|
1755
|
-
try {
|
|
1756
|
-
const l = await lr(u), f = {
|
|
1757
|
-
name: e,
|
|
1758
|
-
query: u,
|
|
1759
|
-
tree: l
|
|
1760
|
-
};
|
|
1761
|
-
return i.fsSnapshots.set(e, f), {
|
|
1762
|
-
fsSnapshot: f,
|
|
1763
|
-
queryCreated: c
|
|
1764
|
-
};
|
|
1765
|
-
} catch (l) {
|
|
1766
|
-
return {
|
|
1767
|
-
error: `Failed to create filesystem snapshot: ${l instanceof Error ? l.message : "Unknown error"}`
|
|
1768
|
-
};
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
function ur(t, r) {
|
|
1772
|
-
t(
|
|
1773
|
-
"fs-snapshot-create",
|
|
1774
|
-
{
|
|
1775
|
-
title: "Create Filesystem Snapshot",
|
|
1776
|
-
description: "Create a filesystem snapshot. Use this to capture filesystem state for later browsing. Prefer fs-snapshot-browse if you need to immediately create and browse a snapshot",
|
|
1777
|
-
inputSchema: X.shape
|
|
1778
|
-
},
|
|
1779
|
-
async (s, o) => {
|
|
1780
|
-
const e = await Ae(s, r, o);
|
|
1781
|
-
if (e.error != null)
|
|
1782
|
-
return `Method: fs-snapshot-create(${JSON.stringify(s)})
|
|
1783
|
-
❌ Error: ${e.error}`;
|
|
1784
|
-
let n = `Method: fs-snapshot-create(${JSON.stringify(s)})
|
|
1785
|
-
`;
|
|
1786
|
-
return e.queryCreated && (n += `✅ Filesystem snapshot query "${e.fsSnapshot.query.name}" created successfully
|
|
1787
|
-
`), n += `✅ Filesystem snapshot "${e.fsSnapshot.name}" created successfully`, n;
|
|
1788
|
-
}
|
|
1789
|
-
);
|
|
1790
|
-
}
|
|
1791
|
-
class dr {
|
|
1792
|
-
_first = null;
|
|
1793
|
-
_last = null;
|
|
1794
|
-
_size = 0;
|
|
1795
|
-
enqueue(r) {
|
|
1796
|
-
const s = { item: r, next: null };
|
|
1797
|
-
this._last ? this._last.next = s : this._first = s, this._last = s, this._size += 1;
|
|
1798
|
-
}
|
|
1799
|
-
dequeue() {
|
|
1800
|
-
if (!this._first) return null;
|
|
1801
|
-
const r = this._first.item;
|
|
1802
|
-
return this._first = this._first.next, this._first || (this._last = null), this._size -= 1, r;
|
|
1803
|
-
}
|
|
1804
|
-
peek() {
|
|
1805
|
-
return this._first ? this._first.item : null;
|
|
1806
|
-
}
|
|
1807
|
-
isEmpty() {
|
|
1808
|
-
return this._first == null;
|
|
1809
|
-
}
|
|
1810
|
-
size() {
|
|
1811
|
-
return this._size;
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
function fr(t) {
|
|
1815
|
-
const r = new dr(), {
|
|
1816
|
-
tree: s,
|
|
1817
|
-
limits: { maxCountTotal: o, maxTokensTotal: e, maxCountGroup: n, maxTokensGroup: a },
|
|
1818
|
-
indexRangeGroupStrategy: i
|
|
1819
|
-
} = t, u = s.getChilds(s.root);
|
|
1820
|
-
u != null && u.length > 0 && r.enqueue({
|
|
1821
|
-
reportNode: null,
|
|
1822
|
-
node: s.root
|
|
1823
|
-
});
|
|
1824
|
-
let c = null, l = 0, f = 0;
|
|
1825
|
-
for (; !r.isEmpty(); ) {
|
|
1826
|
-
const { reportNode: d, node: m } = r.dequeue(), g = s.getChilds(m);
|
|
1827
|
-
if (g == null || m.countChilds === 0 || g.length !== m.countChilds)
|
|
1828
|
-
throw new Error(
|
|
1829
|
-
"Impossible behavior: nodeChilds is null or length mismatch"
|
|
1830
|
-
);
|
|
1831
|
-
let p = r.size();
|
|
1832
|
-
for (let w = 0; w < g.length; w++)
|
|
1833
|
-
g[w].countChilds > 0 && (p += 1);
|
|
1834
|
-
const y = p * i.tokens;
|
|
1835
|
-
if (o != null && l + m.countChilds + p > o || e != null && f + m.tokensChilds + y > e) {
|
|
1836
|
-
const w = [];
|
|
1837
|
-
let S = null, M = 0;
|
|
1838
|
-
for (let b = 0, x = g.length; b < x; b++) {
|
|
1839
|
-
const $ = g[b], v = M * i.tokens;
|
|
1840
|
-
S != null && // Если общий лимит превышен, то не создаем новую группу, а продолжаем текущую. В случае достижения лимитов, последняя группа может содержать больше элементов, чем указано в лимитах группы, и это допустимо. Главное - дать в отчете полную картину.
|
|
1841
|
-
!(o != null && l + 1 > o || e != null && f + i.tokens > e) && (n != null && S.countGrouped + 1 + M > n || a != null && S.tokensGrouped + $.tokens + v > a) && (w.push(S), l += 1, f += i.tokens, S = null, M = 0), S = i.add(S, $, b), $.countChilds > 0 && (M += 1);
|
|
1842
|
-
}
|
|
1843
|
-
S != null && (w.push(S), l += 1, f += i.tokens);
|
|
1844
|
-
const I = w.map((b) => ({
|
|
1845
|
-
text: i.getReportText(b)
|
|
1846
|
-
}));
|
|
1847
|
-
if (d != null) {
|
|
1848
|
-
if (d.childs != null)
|
|
1849
|
-
throw new Error("Impossible behavior: reportNode.childs != null");
|
|
1850
|
-
d.childs = I;
|
|
1851
|
-
} else {
|
|
1852
|
-
if (c != null)
|
|
1853
|
-
throw new Error("Impossible behavior: reportRootNodes != null");
|
|
1854
|
-
c = I;
|
|
1855
|
-
}
|
|
1856
|
-
} else {
|
|
1857
|
-
l += m.countChilds, f += m.tokensChilds;
|
|
1858
|
-
const w = [];
|
|
1859
|
-
for (let S = 0; S < g.length; S++) {
|
|
1860
|
-
const M = g[S], I = {
|
|
1861
|
-
text: M.text
|
|
1862
|
-
};
|
|
1863
|
-
w.push(I);
|
|
1864
|
-
const b = s.getChilds(M);
|
|
1865
|
-
b != null && b.length > 0 && r.enqueue({
|
|
1866
|
-
reportNode: I,
|
|
1867
|
-
node: M
|
|
1868
|
-
});
|
|
1869
|
-
}
|
|
1870
|
-
if (d != null) {
|
|
1871
|
-
if (d.childs != null)
|
|
1872
|
-
throw new Error("Impossible behavior: reportNode.childs != null");
|
|
1873
|
-
d.childs = w;
|
|
1874
|
-
} else {
|
|
1875
|
-
if (c != null)
|
|
1876
|
-
throw new Error("Impossible behavior: reportRootNodes != null");
|
|
1877
|
-
c = w;
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
return c ?? [];
|
|
1882
|
-
}
|
|
1883
|
-
function qe(t) {
|
|
1884
|
-
const {
|
|
1885
|
-
tree: r,
|
|
1886
|
-
request: { parentNodeId: s, childsIndexRange: o, limits: e },
|
|
1887
|
-
indexRangeGroupStrategy: n,
|
|
1888
|
-
...a
|
|
1889
|
-
} = t;
|
|
1890
|
-
let i;
|
|
1891
|
-
if (s != null) {
|
|
1892
|
-
const d = r.getNode(s);
|
|
1893
|
-
if (d == null)
|
|
1894
|
-
throw new Error(`Parent node "${s}" not found`);
|
|
1895
|
-
i = d;
|
|
1896
|
-
} else
|
|
1897
|
-
i = r.root;
|
|
1898
|
-
let u, c = r.getChilds(i) ?? [];
|
|
1899
|
-
if (o != null) {
|
|
1900
|
-
const [d, m] = o;
|
|
1901
|
-
if (d < 0 || m <= d || m >= c.length)
|
|
1902
|
-
throw new Error(
|
|
1903
|
-
`Invalid index range: ${d}-${m} for root nodes length ${c.length}`
|
|
1904
|
-
);
|
|
1905
|
-
const g = [];
|
|
1906
|
-
let p = null;
|
|
1907
|
-
for (let y = d; y <= m; y++) {
|
|
1908
|
-
const w = c[y];
|
|
1909
|
-
g.push(w), p = n.add(p, w, y);
|
|
1910
|
-
}
|
|
1911
|
-
c = g, u = {
|
|
1912
|
-
...i,
|
|
1913
|
-
text: n.getReportText(p),
|
|
1914
|
-
countChilds: p.countGrouped,
|
|
1915
|
-
tokensChilds: p.tokensGrouped
|
|
1916
|
-
};
|
|
1917
|
-
} else
|
|
1918
|
-
u = i;
|
|
1919
|
-
const l = {
|
|
1920
|
-
countChilds: 1,
|
|
1921
|
-
tokensChilds: u.tokens
|
|
1922
|
-
}, f = {
|
|
1923
|
-
...r,
|
|
1924
|
-
root: l,
|
|
1925
|
-
getChilds: (d) => d === l ? [u] : d === u ? c : r.getChilds(d)
|
|
1926
|
-
};
|
|
1927
|
-
return fr({
|
|
1928
|
-
tree: f,
|
|
1929
|
-
limits: e,
|
|
1930
|
-
indexRangeGroupStrategy: n,
|
|
1931
|
-
...a
|
|
1932
|
-
});
|
|
1933
|
-
}
|
|
1934
|
-
function Ge(t, r) {
|
|
1935
|
-
if (t == null || t.length === 0)
|
|
1936
|
-
return "No results found";
|
|
1937
|
-
let s = "";
|
|
1938
|
-
function o(e, n) {
|
|
1939
|
-
for (let a = 0, i = e.length; a < i; a++) {
|
|
1940
|
-
const u = e[a];
|
|
1941
|
-
s += n, s += u.text.textOpen + `
|
|
1942
|
-
`, u.childs != null && u.childs.length > 0 && o(
|
|
1943
|
-
u.childs,
|
|
1944
|
-
u.text.indent ? n + " " : n
|
|
1945
|
-
), u.text.textClose != null && (s += n, s += u.text.textClose + `
|
|
1946
|
-
`);
|
|
1947
|
-
}
|
|
1948
|
-
}
|
|
1949
|
-
return o(t, ""), s;
|
|
1950
|
-
}
|
|
1951
|
-
class mr {
|
|
1952
|
-
tokens = 16;
|
|
1953
|
-
// +1 indent, +1 for line break
|
|
1954
|
-
getReportText = (r) => ({
|
|
1955
|
-
indent: !0,
|
|
1956
|
-
textOpen: `[${r.indexRange[0]}-${r.indexRange[1]}] ${r.countMatched} matched ${r.tokensGrouped} tokens`,
|
|
1957
|
-
textClose: null
|
|
1958
|
-
});
|
|
1959
|
-
add = (r, s, o) => r == null ? {
|
|
1960
|
-
indexRange: [o, o],
|
|
1961
|
-
countGrouped: 1,
|
|
1962
|
-
countMatched: s.countMatched,
|
|
1963
|
-
tokensGrouped: s.tokens
|
|
1964
|
-
} : (r.indexRange[1] = o, r.countGrouped += 1, r.countMatched += s.countMatched, r.tokensGrouped += s.tokens, r);
|
|
1965
|
-
}
|
|
1966
|
-
const je = h.object({
|
|
1967
|
-
snapshotName: h.string().optional().describe("Name of previously created filesystem snapshot, to use"),
|
|
1968
|
-
snapshot: X.optional().describe(
|
|
1969
|
-
"Filesystem snapshot creation options JSON to automatically create snapshot"
|
|
1970
|
-
),
|
|
1971
|
-
parentPath: h.string().optional().describe(
|
|
1972
|
-
"Path relative to snapshot rootDir to browse. Omit to browse the rootDir itself"
|
|
1973
|
-
),
|
|
1974
|
-
childsIndexRange: h.tuple([h.number(), h.number()]).optional().describe(
|
|
1975
|
-
"Child index range to show [start, end]. Only use the exact ranges that appeared in previous snapshot results - do not modify, combine, or split them"
|
|
1976
|
-
)
|
|
1977
|
-
// maxCountTotal: z
|
|
1978
|
-
// .number()
|
|
1979
|
-
// .default(100)
|
|
1980
|
-
// .describe('Maximum total number of items to show'),
|
|
1981
|
-
// maxTokensTotal: z
|
|
1982
|
-
// .number()
|
|
1983
|
-
// .default(10000)
|
|
1984
|
-
// .describe('Maximum total tokens to show'),
|
|
1985
|
-
// maxCountGroup: z.number().default(10).describe('Maximum items per group'),
|
|
1986
|
-
// maxTokensGroup: z.number().default(1000).describe('Maximum tokens per group'),
|
|
1987
|
-
});
|
|
1988
|
-
async function hr(t, r, s) {
|
|
1989
|
-
let o;
|
|
1990
|
-
try {
|
|
1991
|
-
o = je.parse(t);
|
|
1992
|
-
} catch (p) {
|
|
1993
|
-
return {
|
|
1994
|
-
error: C(p)
|
|
1995
|
-
};
|
|
1996
|
-
}
|
|
1997
|
-
const {
|
|
1998
|
-
snapshotName: e,
|
|
1999
|
-
snapshot: n,
|
|
2000
|
-
childsIndexRange: a
|
|
2001
|
-
// maxCountTotal,
|
|
2002
|
-
// maxTokensTotal,
|
|
2003
|
-
// maxCountGroup,
|
|
2004
|
-
// maxTokensGroup,
|
|
2005
|
-
} = o, i = 60, u = 1e3, c = 25, l = 900;
|
|
2006
|
-
if (!s.sessionId)
|
|
2007
|
-
return {
|
|
2008
|
-
error: "Session ID is required"
|
|
2009
|
-
};
|
|
2010
|
-
const f = V(s.sessionId);
|
|
2011
|
-
let d, m = !1, g = !1;
|
|
2012
|
-
if (e && n)
|
|
2013
|
-
return {
|
|
2014
|
-
error: "Either snapshotName or snapshot must be provided, not both"
|
|
2015
|
-
};
|
|
2016
|
-
if (e) {
|
|
2017
|
-
if (d = f.fsSnapshots.get(e), d == null)
|
|
2018
|
-
return {
|
|
2019
|
-
error: `Filesystem snapshot "${e}" not found`
|
|
2020
|
-
};
|
|
2021
|
-
} else if (n) {
|
|
2022
|
-
const p = await Ae(
|
|
2023
|
-
n,
|
|
2024
|
-
r,
|
|
2025
|
-
s
|
|
2026
|
-
);
|
|
2027
|
-
if (p.error != null)
|
|
2028
|
-
return {
|
|
2029
|
-
error: p.error
|
|
2030
|
-
};
|
|
2031
|
-
d = p.fsSnapshot, m = p.queryCreated, g = !0;
|
|
2032
|
-
} else
|
|
2033
|
-
return {
|
|
2034
|
-
error: "Either snapshotName or snapshot must be provided"
|
|
2035
|
-
};
|
|
2036
|
-
try {
|
|
2037
|
-
const p = W(o.parentPath), y = qe({
|
|
2038
|
-
tree: d.tree,
|
|
2039
|
-
request: {
|
|
2040
|
-
parentNodeId: p,
|
|
2041
|
-
childsIndexRange: a,
|
|
2042
|
-
limits: {
|
|
2043
|
-
maxCountTotal: i,
|
|
2044
|
-
maxTokensTotal: u,
|
|
2045
|
-
maxCountGroup: c,
|
|
2046
|
-
maxTokensGroup: l
|
|
2047
|
-
}
|
|
2048
|
-
},
|
|
2049
|
-
indexRangeGroupStrategy: new mr()
|
|
2050
|
-
}), w = Ge(y);
|
|
2051
|
-
return {
|
|
2052
|
-
fsSnapshot: d,
|
|
2053
|
-
queryCreated: m,
|
|
2054
|
-
snapshotCreated: g,
|
|
2055
|
-
parentPath: p,
|
|
2056
|
-
childsIndexRange: a,
|
|
2057
|
-
report: w
|
|
2058
|
-
};
|
|
2059
|
-
} catch (p) {
|
|
2060
|
-
return {
|
|
2061
|
-
error: `Failed to browse filesystem snapshot: ${p instanceof Error ? p.message : "Unknown error"}`
|
|
2062
|
-
};
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
|
-
function pr(t, r) {
|
|
2066
|
-
t(
|
|
2067
|
-
"fs-snapshot-browse",
|
|
2068
|
-
{
|
|
2069
|
-
title: "Browse Filesystem Snapshot",
|
|
2070
|
-
description: "Browse and explore filesystem. Use this to efficiently browse, analyze, explore, inspect, etc directory and file structures",
|
|
2071
|
-
inputSchema: je.shape
|
|
2072
|
-
},
|
|
2073
|
-
async (s, o) => {
|
|
2074
|
-
const e = await hr(s, r, o);
|
|
2075
|
-
if (e.error != null)
|
|
2076
|
-
return `Method: fs-snapshot-browse(${JSON.stringify(s)})
|
|
2077
|
-
❌ Error: ${e.error}`;
|
|
2078
|
-
let n = `Method: fs-snapshot-browse(${JSON.stringify(s)})
|
|
2079
|
-
`;
|
|
2080
|
-
if (e.queryCreated && (n += `✅ Filesystem snapshot query "${e.fsSnapshot.query.name}" created successfully
|
|
2081
|
-
`), e.snapshotCreated && (n += `✅ Filesystem snapshot "${e.fsSnapshot.name}" created successfully
|
|
2082
|
-
`), n += `✅ Browsing filesystem snapshot "${e.fsSnapshot.name}":
|
|
2083
|
-
`, n += `Root directory (<root>/): ${e.fsSnapshot.query.rootDir || "./"}
|
|
2084
|
-
`, n += `Parent path: ${"./" + (e.parentPath ?? "")}
|
|
2085
|
-
`, n += `Fields: ${e.fsSnapshot.query.fields.map((a) => a === "dateModified" ? "lastModified" : a).join(" ")}
|
|
2086
|
-
`, e.childsIndexRange) {
|
|
2087
|
-
const [a, i] = e.childsIndexRange, c = (e.parentPath ? e.fsSnapshot.tree.getNode(e.parentPath) : e.fsSnapshot.tree.root).countChilds;
|
|
2088
|
-
n += ` Showing indexes: ${a}-${i} of ${c}
|
|
2089
|
-
`;
|
|
2090
|
-
}
|
|
2091
|
-
return n += `
|
|
2092
|
-
${e.report}`, n;
|
|
2093
|
-
}
|
|
2094
|
-
);
|
|
2095
|
-
}
|
|
2096
|
-
function gr(t, r) {
|
|
2097
|
-
r.list && er(t, r), r.snapshotQueryCreate && rr(t, r), r.snapshotCreate && ur(t, r), r.snapshotBrowse && pr(t, r), console.log(
|
|
2098
|
-
`File manager:
|
|
2099
|
-
- Working directory: ${T.resolve(r.workingDir || "")}
|
|
2100
|
-
`
|
|
2101
|
-
);
|
|
2102
|
-
}
|
|
2103
|
-
const J = /* @__PURE__ */ new Map();
|
|
2104
|
-
function D(t) {
|
|
2105
|
-
return J.has(t) || J.set(t, {
|
|
2106
|
-
browsers: /* @__PURE__ */ new Map(),
|
|
2107
|
-
domSnapshotQueries: /* @__PURE__ */ new Map()
|
|
2108
|
-
}), J.get(t);
|
|
2109
|
-
}
|
|
2110
|
-
const ee = h.object({
|
|
2111
|
-
name: h.string().describe(
|
|
2112
|
-
"Unique name for the browser. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
2113
|
-
),
|
|
2114
|
-
browserType: h.enum(["chromium", "firefox", "webkit"]).describe("Browser type to launch"),
|
|
2115
|
-
muteAudio: h.boolean().optional().describe("Mute audio in the browser"),
|
|
2116
|
-
devTools: h.boolean().optional().describe("Open browser with dev tools")
|
|
2117
|
-
});
|
|
2118
|
-
async function _e(t, r, s) {
|
|
2119
|
-
let o;
|
|
2120
|
-
try {
|
|
2121
|
-
o = ee.parse(t);
|
|
2122
|
-
} catch (l) {
|
|
2123
|
-
return {
|
|
2124
|
-
error: C(l)
|
|
2125
|
-
};
|
|
2126
|
-
}
|
|
2127
|
-
const { name: e, browserType: n, muteAudio: a, devTools: i } = o;
|
|
2128
|
-
if (!s.sessionId)
|
|
2129
|
-
return {
|
|
2130
|
-
error: "Session ID is required"
|
|
2131
|
-
};
|
|
2132
|
-
const u = D(s.sessionId), c = u.browsers.get(e);
|
|
2133
|
-
if (c)
|
|
2134
|
-
return {
|
|
2135
|
-
error: `Browser "${c.name}" (${c.browserType}) already exists`
|
|
2136
|
-
};
|
|
2137
|
-
try {
|
|
2138
|
-
const f = await {
|
|
2139
|
-
chromium: gt,
|
|
2140
|
-
firefox: pt,
|
|
2141
|
-
webkit: ht
|
|
2142
|
-
}[n].launch({
|
|
2143
|
-
headless: !1,
|
|
2144
|
-
devtools: i,
|
|
2145
|
-
args: a ? ["--mute-audio"] : void 0
|
|
2146
|
-
}), d = {
|
|
2147
|
-
name: e,
|
|
2148
|
-
browserType: n,
|
|
2149
|
-
browser: f,
|
|
2150
|
-
contexts: /* @__PURE__ */ new Map()
|
|
2151
|
-
};
|
|
2152
|
-
return u.browsers.set(e, d), { browserInfo: d };
|
|
2153
|
-
} catch (l) {
|
|
2154
|
-
return {
|
|
2155
|
-
error: `Failed to create browser: ${l instanceof Error ? l.message : "Unknown error"}`
|
|
2156
|
-
};
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
function wr(t, r) {
|
|
2160
|
-
t(
|
|
2161
|
-
"playwright-browser-create",
|
|
2162
|
-
{
|
|
2163
|
-
title: "Create Browser",
|
|
2164
|
-
description: "Create a new browser. Prefer page-goto if you need to immediately create a browser, context, page and navigate",
|
|
2165
|
-
inputSchema: ee.shape
|
|
2166
|
-
},
|
|
2167
|
-
async (s, o) => {
|
|
2168
|
-
const e = await _e(s, r, o);
|
|
2169
|
-
return `Method: playwright-browser-create(${JSON.stringify(s)})
|
|
2170
|
-
${e.error != null ? `❌ Error: ${e.error}` : `✅ Browser "${e.browserInfo.name}" (${e.browserInfo.browserType}) created successfully`}`;
|
|
2171
|
-
}
|
|
2172
|
-
);
|
|
2173
|
-
}
|
|
2174
|
-
const Je = h.object({});
|
|
2175
|
-
async function yr(t, r, s) {
|
|
2176
|
-
let o;
|
|
2177
|
-
try {
|
|
2178
|
-
o = Je.parse(t);
|
|
2179
|
-
} catch (a) {
|
|
2180
|
-
return {
|
|
2181
|
-
error: C(a)
|
|
2182
|
-
};
|
|
2183
|
-
}
|
|
2184
|
-
if (!s.sessionId)
|
|
2185
|
-
return {
|
|
2186
|
-
error: "Session ID is required"
|
|
2187
|
-
};
|
|
2188
|
-
const e = D(s.sessionId);
|
|
2189
|
-
return {
|
|
2190
|
-
browserInfos: Array.from(e.browsers.values())
|
|
2191
|
-
};
|
|
2192
|
-
}
|
|
2193
|
-
function br(t, r) {
|
|
2194
|
-
t(
|
|
2195
|
-
"playwright-browser-list",
|
|
2196
|
-
{
|
|
2197
|
-
title: "List Browsers",
|
|
2198
|
-
description: "List active browser instances",
|
|
2199
|
-
inputSchema: Je.shape
|
|
2200
|
-
},
|
|
2201
|
-
async (s, o) => {
|
|
2202
|
-
const e = await yr(s, r, o);
|
|
2203
|
-
if (e.error != null)
|
|
2204
|
-
return `Method: playwright-browser-list(${JSON.stringify(s)})
|
|
2205
|
-
❌ Error: ${e.error}`;
|
|
2206
|
-
const n = e.browserInfos.map(
|
|
2207
|
-
(a) => `${a.name} (${a.browserType})`
|
|
2208
|
-
);
|
|
2209
|
-
return `Method: playwright-browser-list(${JSON.stringify(s)})
|
|
2210
|
-
${n.length === 0 ? "No browsers found" : `Browsers: ${n.join(", ")}`}`;
|
|
2211
|
-
}
|
|
2212
|
-
);
|
|
2213
|
-
}
|
|
2214
|
-
const Ke = h.object({
|
|
2215
|
-
names: h.array(h.string()).optional().describe(
|
|
2216
|
-
"Names of browsers to close. If not specified, closes all browsers"
|
|
2217
|
-
)
|
|
2218
|
-
});
|
|
2219
|
-
async function Sr(t, r, s) {
|
|
2220
|
-
let o;
|
|
2221
|
-
try {
|
|
2222
|
-
o = Ke.parse(t);
|
|
2223
|
-
} catch (c) {
|
|
2224
|
-
return {
|
|
2225
|
-
error: C(c)
|
|
2226
|
-
};
|
|
2227
|
-
}
|
|
2228
|
-
const { names: e } = o;
|
|
2229
|
-
if (!s.sessionId)
|
|
2230
|
-
return {
|
|
2231
|
-
error: "Session ID is required"
|
|
2232
|
-
};
|
|
2233
|
-
const n = D(s.sessionId), a = [], i = [];
|
|
2234
|
-
let u = [];
|
|
2235
|
-
return e ? e.forEach((c) => {
|
|
2236
|
-
const l = n.browsers.get(c);
|
|
2237
|
-
l ? u.push(l) : i.push(`Browser "${c}" not found`);
|
|
2238
|
-
}) : u = Array.from(n.browsers.values()), await Promise.all(
|
|
2239
|
-
u.map(async (c) => {
|
|
2240
|
-
try {
|
|
2241
|
-
await c.browser.close(), n.browsers.delete(c.name), a.push(c);
|
|
2242
|
-
} catch (l) {
|
|
2243
|
-
i.push(
|
|
2244
|
-
`Failed to close browser "${c.name}" (${c.browserType}): ${l instanceof Error ? l.message : "Unknown error"}`
|
|
2245
|
-
);
|
|
2246
|
-
}
|
|
2247
|
-
})
|
|
2248
|
-
), {
|
|
2249
|
-
closedBrowserInfos: a,
|
|
2250
|
-
...i.length > 0 && { errors: i }
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
function xr(t, r) {
|
|
2254
|
-
t(
|
|
2255
|
-
"playwright-browser-close",
|
|
2256
|
-
{
|
|
2257
|
-
title: "Close Browsers",
|
|
2258
|
-
description: "Close browsers. Automatically closes all contexts and pages within the browsers",
|
|
2259
|
-
inputSchema: Ke.shape
|
|
2260
|
-
},
|
|
2261
|
-
async (s, o) => {
|
|
2262
|
-
const e = await Sr(s, r, o);
|
|
2263
|
-
if (e.error != null)
|
|
2264
|
-
return `Method: playwright-browser-close(${JSON.stringify(s)})
|
|
2265
|
-
❌ Error: ${e.error}`;
|
|
2266
|
-
const n = [];
|
|
2267
|
-
if (e.closedBrowserInfos.length > 0) {
|
|
2268
|
-
const a = e.closedBrowserInfos.map(
|
|
2269
|
-
(i) => `${i.name} (${i.browserType})`
|
|
2270
|
-
);
|
|
2271
|
-
n.push(`✅ Closed browsers: ${a.join(", ")}`);
|
|
2272
|
-
}
|
|
2273
|
-
return e.errors && e.errors.length > 0 && (n.length > 0 && n.push(""), n.push("❌ Errors:"), e.errors.forEach((a) => n.push(a))), n.length === 0 && n.push("No browsers to close"), `Method: playwright-browser-close(${JSON.stringify(s)})
|
|
2274
|
-
${n.join(`
|
|
2275
|
-
`)}`;
|
|
2276
|
-
}
|
|
2277
|
-
);
|
|
2278
|
-
}
|
|
2279
|
-
const te = h.object({
|
|
2280
|
-
browserName: h.string().optional().describe("Name of previously created browser, to use"),
|
|
2281
|
-
browser: ee.optional().describe(
|
|
2282
|
-
"Browser creation options JSON to automatically create browser"
|
|
2283
|
-
),
|
|
2284
|
-
name: h.string().describe(
|
|
2285
|
-
"Unique name for the context. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
2286
|
-
),
|
|
2287
|
-
isMobile: h.boolean().optional().describe("Configure for mobile device simulation"),
|
|
2288
|
-
hasTouch: h.boolean().optional().describe("Enable touch events"),
|
|
2289
|
-
viewport: h.object({
|
|
2290
|
-
width: h.number(),
|
|
2291
|
-
height: h.number()
|
|
2292
|
-
}).optional().describe("Viewport size configuration")
|
|
2293
|
-
});
|
|
2294
|
-
async function We(t, r, s) {
|
|
2295
|
-
let o;
|
|
2296
|
-
try {
|
|
2297
|
-
o = te.parse(t);
|
|
2298
|
-
} catch (m) {
|
|
2299
|
-
return {
|
|
2300
|
-
error: C(m)
|
|
2301
|
-
};
|
|
2302
|
-
}
|
|
2303
|
-
const { name: e, browserName: n, browser: a, isMobile: i, hasTouch: u, viewport: c } = o;
|
|
2304
|
-
if (!s.sessionId)
|
|
2305
|
-
return {
|
|
2306
|
-
error: "Session ID is required"
|
|
2307
|
-
};
|
|
2308
|
-
const l = D(s.sessionId);
|
|
2309
|
-
if (n && a)
|
|
2310
|
-
return {
|
|
2311
|
-
error: "Either browserName or browser must be provided, not both"
|
|
2312
|
-
};
|
|
2313
|
-
let f = !1, d;
|
|
2314
|
-
if (n) {
|
|
2315
|
-
if (d = l.browsers.get(n), !d)
|
|
2316
|
-
return {
|
|
2317
|
-
error: `Browser "${n}" not found`
|
|
2318
|
-
};
|
|
2319
|
-
} else if (a) {
|
|
2320
|
-
const m = await _e(a, r, s);
|
|
2321
|
-
if (m.error != null)
|
|
2322
|
-
return {
|
|
2323
|
-
error: m.error
|
|
2324
|
-
};
|
|
2325
|
-
d = m.browserInfo, f = !0;
|
|
2326
|
-
} else
|
|
2327
|
-
return {
|
|
2328
|
-
error: "Either browserName or browser must be provided"
|
|
2329
|
-
};
|
|
2330
|
-
if (d.contexts.has(e))
|
|
2331
|
-
return {
|
|
2332
|
-
error: `Context "${e}" already exists in browser "${d.name}" (${d.browserType})`
|
|
2333
|
-
};
|
|
2334
|
-
try {
|
|
2335
|
-
const m = await d.browser.newContext({
|
|
2336
|
-
isMobile: i,
|
|
2337
|
-
hasTouch: u,
|
|
2338
|
-
viewport: c
|
|
2339
|
-
}), g = {
|
|
2340
|
-
browserInfo: d,
|
|
2341
|
-
name: e,
|
|
2342
|
-
context: m,
|
|
2343
|
-
pages: /* @__PURE__ */ new Map()
|
|
2344
|
-
};
|
|
2345
|
-
return d.contexts.set(e, g), {
|
|
2346
|
-
browserInfoCreated: f,
|
|
2347
|
-
browserInfo: d,
|
|
2348
|
-
contextInfo: g
|
|
2349
|
-
};
|
|
2350
|
-
} catch (m) {
|
|
2351
|
-
return {
|
|
2352
|
-
error: `Failed to create context: ${m instanceof Error ? m.message : "Unknown error"} in browser "${d.name}" (${d.browserType})`
|
|
2353
|
-
};
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
function $r(t, r) {
|
|
2357
|
-
t(
|
|
2358
|
-
"playwright-context-create",
|
|
2359
|
-
{
|
|
2360
|
-
title: "Create Browser Context",
|
|
2361
|
-
description: "Create a new browser context. Prefer page-goto if you need to immediately create a context, page and navigate",
|
|
2362
|
-
inputSchema: te.shape
|
|
2363
|
-
},
|
|
2364
|
-
async (s, o) => {
|
|
2365
|
-
const e = await We(s, r, o);
|
|
2366
|
-
if (e.error != null)
|
|
2367
|
-
return `Method: playwright-context-create(${JSON.stringify(s)})
|
|
2368
|
-
❌ Error: ${e.error}`;
|
|
2369
|
-
let n = `Method: playwright-context-create(${JSON.stringify(s)})
|
|
2370
|
-
`;
|
|
2371
|
-
return e.browserInfoCreated && (n += `✅ Browser "${e.browserInfo.name}" (${e.browserInfo.browserType}) created successfully
|
|
2372
|
-
`), n += `✅ Context "${e.contextInfo.name}" created successfully in browser "${e.contextInfo.browserInfo.name}" (${e.contextInfo.browserInfo.browserType})`, n;
|
|
2373
|
-
}
|
|
2374
|
-
);
|
|
2375
|
-
}
|
|
2376
|
-
const Qe = h.object({
|
|
2377
|
-
browserName: h.string().optional().describe(
|
|
2378
|
-
"Name of browser to list contexts from. If not specified, lists contexts from all browsers"
|
|
2379
|
-
)
|
|
2380
|
-
});
|
|
2381
|
-
async function Ir(t, r, s) {
|
|
2382
|
-
let o;
|
|
2383
|
-
try {
|
|
2384
|
-
o = Qe.parse(t);
|
|
2385
|
-
} catch (i) {
|
|
2386
|
-
return {
|
|
2387
|
-
error: C(i)
|
|
2388
|
-
};
|
|
2389
|
-
}
|
|
2390
|
-
const { browserName: e } = o;
|
|
2391
|
-
if (!s.sessionId)
|
|
2392
|
-
return {
|
|
2393
|
-
error: "Session ID is required"
|
|
2394
|
-
};
|
|
2395
|
-
const n = D(s.sessionId), a = [];
|
|
2396
|
-
if (e) {
|
|
2397
|
-
const i = n.browsers.get(e);
|
|
2398
|
-
if (!i)
|
|
2399
|
-
return {
|
|
2400
|
-
error: `Browser "${e}" not found`
|
|
2401
|
-
};
|
|
2402
|
-
Array.from(i.contexts.values()).length > 0 && a.push({
|
|
2403
|
-
browserInfo: i,
|
|
2404
|
-
contexts: Array.from(i.contexts.values())
|
|
2405
|
-
});
|
|
2406
|
-
} else
|
|
2407
|
-
for (const i of n.browsers.values()) {
|
|
2408
|
-
const u = Array.from(i.contexts.values());
|
|
2409
|
-
u.length > 0 && a.push({
|
|
2410
|
-
browserInfo: i,
|
|
2411
|
-
contexts: u
|
|
2412
|
-
});
|
|
2413
|
-
}
|
|
2414
|
-
return {
|
|
2415
|
-
contextsByBrowser: a
|
|
2416
|
-
};
|
|
2417
|
-
}
|
|
2418
|
-
function Mr(t, r) {
|
|
2419
|
-
t(
|
|
2420
|
-
"playwright-context-list",
|
|
2421
|
-
{
|
|
2422
|
-
title: "List Browser Contexts",
|
|
2423
|
-
description: "List active browser contexts",
|
|
2424
|
-
inputSchema: Qe.shape
|
|
2425
|
-
},
|
|
2426
|
-
async (s, o) => {
|
|
2427
|
-
const e = await Ir(s, r, o);
|
|
2428
|
-
if ("error" in e)
|
|
2429
|
-
return `Method: playwright-context-list(${JSON.stringify(s)})
|
|
2430
|
-
❌ Error: ${e.error}`;
|
|
2431
|
-
let n = `Method: playwright-context-list(${JSON.stringify(s)})
|
|
2432
|
-
`;
|
|
2433
|
-
return e.contextsByBrowser.length === 0 ? n += "No contexts found" : n += e.contextsByBrowser.map(
|
|
2434
|
-
({ browserInfo: a, contexts: i }) => `${a.name} (${a.browserType}): ${i.map((u) => u.name).join(", ")}`
|
|
2435
|
-
).join(`
|
|
2436
|
-
`), n;
|
|
2437
|
-
}
|
|
2438
|
-
);
|
|
2439
|
-
}
|
|
2440
|
-
const He = h.object({
|
|
2441
|
-
names: h.array(h.string()).optional().describe(
|
|
2442
|
-
"Names of contexts to close. If not specified, closes all contexts"
|
|
2443
|
-
),
|
|
2444
|
-
browserName: h.string().optional().describe(
|
|
2445
|
-
"Name of browser to close contexts from. If not specified, searches all browsers"
|
|
2446
|
-
)
|
|
2447
|
-
});
|
|
2448
|
-
async function Tr(t, r, s) {
|
|
2449
|
-
let o;
|
|
2450
|
-
try {
|
|
2451
|
-
o = He.parse(t);
|
|
2452
|
-
} catch (l) {
|
|
2453
|
-
return {
|
|
2454
|
-
error: C(l)
|
|
2455
|
-
};
|
|
2456
|
-
}
|
|
2457
|
-
const { names: e, browserName: n } = o;
|
|
2458
|
-
if (!s.sessionId)
|
|
2459
|
-
return {
|
|
2460
|
-
error: "Session ID is required"
|
|
2461
|
-
};
|
|
2462
|
-
const a = D(s.sessionId), i = [], u = [];
|
|
2463
|
-
let c = [];
|
|
2464
|
-
if (n) {
|
|
2465
|
-
const l = a.browsers.get(n);
|
|
2466
|
-
if (!l)
|
|
2467
|
-
return {
|
|
2468
|
-
error: `Browser "${n}" not found`
|
|
2469
|
-
};
|
|
2470
|
-
e ? e.forEach((f) => {
|
|
2471
|
-
const d = l.contexts.get(f);
|
|
2472
|
-
d ? c.push(d) : u.push(
|
|
2473
|
-
`Context "${f}" not found in browser "${l.name}" (${l.browserType})`
|
|
2474
|
-
);
|
|
2475
|
-
}) : c = Array.from(l.contexts.values());
|
|
2476
|
-
} else if (e)
|
|
2477
|
-
for (const l of a.browsers.values())
|
|
2478
|
-
e.forEach((f) => {
|
|
2479
|
-
const d = l.contexts.get(f);
|
|
2480
|
-
d ? c.push(d) : u.push(
|
|
2481
|
-
`Context "${f}" not found in browser "${l.name}" (${l.browserType})`
|
|
2482
|
-
);
|
|
2483
|
-
});
|
|
2484
|
-
else
|
|
2485
|
-
for (const l of a.browsers.values())
|
|
2486
|
-
c.push(...Array.from(l.contexts.values()));
|
|
2487
|
-
return await Promise.all(
|
|
2488
|
-
c.map(async (l) => {
|
|
2489
|
-
try {
|
|
2490
|
-
await l.context.close(), l.browserInfo.contexts.delete(l.name), i.push(l);
|
|
2491
|
-
} catch (f) {
|
|
2492
|
-
u.push(
|
|
2493
|
-
`Failed to close context "${l.name}" (${l.browserInfo.name}) (${l.browserInfo.browserType}): ${f instanceof Error ? f.message : "Unknown error"}`
|
|
2494
|
-
);
|
|
2495
|
-
}
|
|
2496
|
-
})
|
|
2497
|
-
), {
|
|
2498
|
-
closedContextInfos: i,
|
|
2499
|
-
...u.length > 0 && { errors: u }
|
|
2500
|
-
};
|
|
2501
|
-
}
|
|
2502
|
-
function vr(t, r) {
|
|
2503
|
-
t(
|
|
2504
|
-
"playwright-context-close",
|
|
2505
|
-
{
|
|
2506
|
-
title: "Close Browser Contexts",
|
|
2507
|
-
description: "Close browser contexts. Automatically closes all pages within the contexts",
|
|
2508
|
-
inputSchema: He.shape
|
|
2509
|
-
},
|
|
2510
|
-
async (s, o) => {
|
|
2511
|
-
const e = await Tr(s, r, o);
|
|
2512
|
-
if ("error" in e)
|
|
2513
|
-
return `Method: playwright-context-close(${JSON.stringify(s)})
|
|
2514
|
-
❌ Error: ${e.error}`;
|
|
2515
|
-
const n = [];
|
|
2516
|
-
if (e.closedContextInfos.length > 0) {
|
|
2517
|
-
const a = e.closedContextInfos.map(
|
|
2518
|
-
(i) => `${i.name} (${i.browserInfo.name}) (${i.browserInfo.browserType})`
|
|
2519
|
-
);
|
|
2520
|
-
n.push(`✅ Closed contexts: ${a.join(", ")}`);
|
|
2521
|
-
}
|
|
2522
|
-
return e.errors && e.errors.length > 0 && (n.length > 0 && n.push(""), n.push("❌ Errors:"), e.errors.forEach((a) => n.push(a))), n.length === 0 && n.push("No contexts to close"), `Method: playwright-context-close(${JSON.stringify(s)})
|
|
2523
|
-
${n.join(`
|
|
2524
|
-
`)}`;
|
|
2525
|
-
}
|
|
2526
|
-
);
|
|
2527
|
-
}
|
|
2528
|
-
function Cr() {
|
|
2529
|
-
class t {
|
|
2530
|
-
prevId = 0;
|
|
2531
|
-
objectToId = /* @__PURE__ */ new WeakMap();
|
|
2532
|
-
idToObject = /* @__PURE__ */ new Map();
|
|
2533
|
-
cleanupRegistry;
|
|
2534
|
-
constructor() {
|
|
2535
|
-
this.cleanupRegistry = new FinalizationRegistry((u) => {
|
|
2536
|
-
this.idToObject.delete(u);
|
|
2537
|
-
});
|
|
2538
|
-
}
|
|
2539
|
-
getOrCreateId(u) {
|
|
2540
|
-
let c = this.objectToId.get(u);
|
|
2541
|
-
return c == null && (c = ++this.prevId, this.objectToId.set(u, c), this.idToObject.set(c, new WeakRef(u)), this.cleanupRegistry.register(u, c)), c;
|
|
2542
|
-
}
|
|
2543
|
-
getObject(u) {
|
|
2544
|
-
const c = this.idToObject.get(u);
|
|
2545
|
-
if (!c)
|
|
2546
|
-
return null;
|
|
2547
|
-
const l = c.deref();
|
|
2548
|
-
return l ?? (this.idToObject.delete(u), null);
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
function r(i, u, c) {
|
|
2552
|
-
let l = null;
|
|
2553
|
-
for (let f = 0, d = u.length; f < d; f++) {
|
|
2554
|
-
const m = u[f], g = i(m), p = g == null ? null : r(i, g, c), y = c(m, p);
|
|
2555
|
-
y != null && (l == null && (l = []), l.push(y));
|
|
2556
|
-
}
|
|
2557
|
-
return l;
|
|
2558
|
-
}
|
|
2559
|
-
function s(i) {
|
|
2560
|
-
const { getId: u, getChilds: c, rootNodes: l, createSnapshotNode: f } = i, d = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Map(), g = /* @__PURE__ */ new Map(), p = r(
|
|
2561
|
-
c,
|
|
2562
|
-
l,
|
|
2563
|
-
(w, S) => {
|
|
2564
|
-
const M = f(w, S);
|
|
2565
|
-
if (w != null && M != null) {
|
|
2566
|
-
const I = u(w);
|
|
2567
|
-
d.set(I, M), m.set(M, I);
|
|
2568
|
-
}
|
|
2569
|
-
return M != null && S != null && g.set(
|
|
2570
|
-
m.get(M),
|
|
2571
|
-
S.map((I) => m.get(I))
|
|
2572
|
-
), M;
|
|
2573
|
-
}
|
|
2574
|
-
), y = f(null, p);
|
|
2575
|
-
if (y == null)
|
|
2576
|
-
throw new Error("Impossible behavior: rootNode == null");
|
|
2577
|
-
return d.set(null, y), p != null && g.set(
|
|
2578
|
-
null,
|
|
2579
|
-
p.map((w) => m.get(w))
|
|
2580
|
-
), {
|
|
2581
|
-
idToNode: d,
|
|
2582
|
-
idToChildIds: g
|
|
2583
|
-
};
|
|
2584
|
-
}
|
|
2585
|
-
const o = (i) => i instanceof HTMLElement ? i.childNodes : null;
|
|
2586
|
-
function e(i) {
|
|
2587
|
-
return function(c, l) {
|
|
2588
|
-
const f = l != null && l.length > 0;
|
|
2589
|
-
let d = !1, m = null, g = null;
|
|
2590
|
-
if (c instanceof HTMLElement) {
|
|
2591
|
-
if (m = n.getOrCreateId(c), g = c.tagName.toLowerCase(), d = c.matches(i.cssSelector), !d && !f)
|
|
2592
|
-
return null;
|
|
2593
|
-
} else if (c == null)
|
|
2594
|
-
m = null, g = null, d = !1;
|
|
2595
|
-
else
|
|
2596
|
-
return null;
|
|
2597
|
-
return {
|
|
2598
|
-
uid: m,
|
|
2599
|
-
tagName: g,
|
|
2600
|
-
isMatched: d
|
|
2601
|
-
};
|
|
2602
|
-
};
|
|
2603
|
-
}
|
|
2604
|
-
const n = new t();
|
|
2605
|
-
function a(i) {
|
|
2606
|
-
const u = e(i);
|
|
2607
|
-
return s({
|
|
2608
|
-
getId: (c) => n.getOrCreateId(c),
|
|
2609
|
-
getChilds: o,
|
|
2610
|
-
createSnapshotNode: u,
|
|
2611
|
-
rootNodes: [window.document.documentElement]
|
|
2612
|
-
});
|
|
2613
|
-
}
|
|
2614
|
-
window.__mcp_playwright_tool_tx4byhar35_createDomSnapshotTreeRawDom = a;
|
|
2615
|
-
}
|
|
2616
|
-
const kr = `(function (){function __name(fn){return fn};${Cr.toString()}; setupPageGlobals();})()`, re = h.object({
|
|
2617
|
-
contextName: h.string().optional().describe("Name of previously created context, to use"),
|
|
2618
|
-
context: te.optional().describe(
|
|
2619
|
-
"Context creation options JSON to automatically create context"
|
|
2620
|
-
),
|
|
2621
|
-
name: h.string().describe(
|
|
2622
|
-
"Unique name for the page. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
2623
|
-
)
|
|
2624
|
-
});
|
|
2625
|
-
async function Ye(t, r, s) {
|
|
2626
|
-
let o;
|
|
2627
|
-
try {
|
|
2628
|
-
o = re.parse(t);
|
|
2629
|
-
} catch (f) {
|
|
2630
|
-
return {
|
|
2631
|
-
error: C(f)
|
|
2632
|
-
};
|
|
2633
|
-
}
|
|
2634
|
-
const { name: e, contextName: n, context: a } = o;
|
|
2635
|
-
if (!s.sessionId)
|
|
2636
|
-
return {
|
|
2637
|
-
error: "Session ID is required"
|
|
2638
|
-
};
|
|
2639
|
-
const i = D(s.sessionId);
|
|
2640
|
-
if (n && a)
|
|
2641
|
-
return {
|
|
2642
|
-
error: "Either contextName or context must be provided, not both"
|
|
2643
|
-
};
|
|
2644
|
-
let u = !1, c = !1, l;
|
|
2645
|
-
if (n) {
|
|
2646
|
-
for (const f of i.browsers.values())
|
|
2647
|
-
if (f.contexts.has(n)) {
|
|
2648
|
-
l = f.contexts.get(n);
|
|
2649
|
-
break;
|
|
2650
|
-
}
|
|
2651
|
-
if (!l)
|
|
2652
|
-
return {
|
|
2653
|
-
error: `Context "${n}" not found`
|
|
2654
|
-
};
|
|
2655
|
-
} else if (a) {
|
|
2656
|
-
const f = await We(a, r, s);
|
|
2657
|
-
if (f.error != null)
|
|
2658
|
-
return {
|
|
2659
|
-
error: f.error
|
|
2660
|
-
};
|
|
2661
|
-
l = f.contextInfo, u = f.browserInfoCreated, c = !0;
|
|
2662
|
-
} else
|
|
2663
|
-
return {
|
|
2664
|
-
error: "Either contextName or context must be provided"
|
|
2665
|
-
};
|
|
2666
|
-
if (l.pages.has(e))
|
|
2667
|
-
return {
|
|
2668
|
-
error: `Page "${e}" already exists in context "${l.name}" in browser "${l.browserInfo.name}" (${l.browserInfo.browserType})`
|
|
2669
|
-
};
|
|
2670
|
-
try {
|
|
2671
|
-
const f = await l.context.newPage();
|
|
2672
|
-
await f.addInitScript(kr), await f.goto("about:blank");
|
|
2673
|
-
const d = {
|
|
2674
|
-
contextInfo: l,
|
|
2675
|
-
name: e,
|
|
2676
|
-
page: f,
|
|
2677
|
-
domSnapshots: /* @__PURE__ */ new Map()
|
|
2678
|
-
};
|
|
2679
|
-
return l.pages.set(e, d), {
|
|
2680
|
-
browserInfoCreated: u,
|
|
2681
|
-
contextInfoCreated: c,
|
|
2682
|
-
pageInfo: d
|
|
2683
|
-
};
|
|
2684
|
-
} catch (f) {
|
|
2685
|
-
return {
|
|
2686
|
-
error: `Failed to create page: ${f instanceof Error ? f.message : "Unknown error"} in context "${l.name}" in browser "${l.browserInfo.name}" (${l.browserInfo.browserType})`
|
|
2687
|
-
};
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
function Nr(t, r) {
|
|
2691
|
-
t(
|
|
2692
|
-
"playwright-page-create",
|
|
2693
|
-
{
|
|
2694
|
-
title: "Create Page",
|
|
2695
|
-
description: "Create a new page. Prefer page-goto if you need to immediately create a page and navigate",
|
|
2696
|
-
inputSchema: re.shape
|
|
2697
|
-
},
|
|
2698
|
-
async (s, o) => {
|
|
2699
|
-
const e = await Ye(s, r, o);
|
|
2700
|
-
if (e.error != null)
|
|
2701
|
-
return `Method: playwright-page-create(${JSON.stringify(s)})
|
|
2702
|
-
❌ Error: ${e.error}`;
|
|
2703
|
-
let n = `Method: playwright-page-create(${JSON.stringify(s)})
|
|
2704
|
-
`;
|
|
2705
|
-
return e.browserInfoCreated && (n += `✅ Browser "${e.pageInfo.contextInfo.browserInfo.name}" (${e.pageInfo.contextInfo.browserInfo.browserType}) created successfully
|
|
2706
|
-
`), e.contextInfoCreated && (n += `✅ Context "${e.pageInfo.contextInfo.name}" created successfully in browser "${e.pageInfo.contextInfo.browserInfo.name}" (${e.pageInfo.contextInfo.browserInfo.browserType})
|
|
2707
|
-
`), n += `✅ Page "${e.pageInfo.name}" created successfully in context "${e.pageInfo.contextInfo.name}" in browser "${e.pageInfo.contextInfo.browserInfo.name}" (${e.pageInfo.contextInfo.browserInfo.browserType})`, n;
|
|
2708
|
-
}
|
|
2709
|
-
);
|
|
2710
|
-
}
|
|
2711
|
-
const Ve = h.object({
|
|
2712
|
-
contextName: h.string().optional().describe(
|
|
2713
|
-
"Name of context to list pages from. If not specified, lists pages from all contexts"
|
|
2714
|
-
),
|
|
2715
|
-
browserName: h.string().optional().describe(
|
|
2716
|
-
"Name of browser to search in. If not specified, searches all browsers"
|
|
2717
|
-
)
|
|
2718
|
-
});
|
|
2719
|
-
async function Er(t, r, s) {
|
|
2720
|
-
let o;
|
|
2721
|
-
try {
|
|
2722
|
-
o = Ve.parse(t);
|
|
2723
|
-
} catch (u) {
|
|
2724
|
-
return {
|
|
2725
|
-
error: C(u)
|
|
2726
|
-
};
|
|
2727
|
-
}
|
|
2728
|
-
const { contextName: e, browserName: n } = o;
|
|
2729
|
-
if (!s.sessionId)
|
|
2730
|
-
return {
|
|
2731
|
-
error: "Session ID is required"
|
|
2732
|
-
};
|
|
2733
|
-
const a = D(s.sessionId), i = [];
|
|
2734
|
-
if (n) {
|
|
2735
|
-
const u = a.browsers.get(n);
|
|
2736
|
-
if (!u)
|
|
2737
|
-
return {
|
|
2738
|
-
error: `Browser "${n}" not found`
|
|
2739
|
-
};
|
|
2740
|
-
if (e) {
|
|
2741
|
-
const c = u.contexts.get(e);
|
|
2742
|
-
if (!c)
|
|
2743
|
-
return {
|
|
2744
|
-
error: `Context "${e}" not found in browser "${u.name}" (${u.browserType})`
|
|
2745
|
-
};
|
|
2746
|
-
const l = Array.from(c.pages.values());
|
|
2747
|
-
l.length > 0 && i.push({
|
|
2748
|
-
contextInfo: c,
|
|
2749
|
-
pages: l
|
|
2750
|
-
});
|
|
2751
|
-
} else
|
|
2752
|
-
for (const c of u.contexts.values()) {
|
|
2753
|
-
const l = Array.from(c.pages.values());
|
|
2754
|
-
l.length > 0 && i.push({
|
|
2755
|
-
contextInfo: c,
|
|
2756
|
-
pages: l
|
|
2757
|
-
});
|
|
2758
|
-
}
|
|
2759
|
-
} else if (e)
|
|
2760
|
-
for (const u of a.browsers.values()) {
|
|
2761
|
-
const c = u.contexts.get(e);
|
|
2762
|
-
if (c) {
|
|
2763
|
-
const l = Array.from(c.pages.values());
|
|
2764
|
-
l.length > 0 && i.push({
|
|
2765
|
-
contextInfo: c,
|
|
2766
|
-
pages: l
|
|
2767
|
-
});
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
else
|
|
2771
|
-
for (const u of a.browsers.values())
|
|
2772
|
-
for (const c of u.contexts.values()) {
|
|
2773
|
-
const l = Array.from(c.pages.values());
|
|
2774
|
-
l.length > 0 && i.push({
|
|
2775
|
-
contextInfo: c,
|
|
2776
|
-
pages: l
|
|
2777
|
-
});
|
|
2778
|
-
}
|
|
2779
|
-
return {
|
|
2780
|
-
pagesByContext: i
|
|
2781
|
-
};
|
|
2782
|
-
}
|
|
2783
|
-
function Dr(t, r) {
|
|
2784
|
-
t(
|
|
2785
|
-
"playwright-page-list",
|
|
2786
|
-
{
|
|
2787
|
-
title: "List Pages",
|
|
2788
|
-
description: "List active pages",
|
|
2789
|
-
inputSchema: Ve.shape
|
|
2790
|
-
},
|
|
2791
|
-
async (s, o) => {
|
|
2792
|
-
const e = await Er(s, r, o);
|
|
2793
|
-
if ("error" in e)
|
|
2794
|
-
return `Method: playwright-page-list(${JSON.stringify(s)})
|
|
2795
|
-
❌ Error: ${e.error}`;
|
|
2796
|
-
let n = `Method: playwright-page-list(${JSON.stringify(s)})
|
|
2797
|
-
`;
|
|
2798
|
-
return e.pagesByContext.length === 0 ? n += "No pages found" : n += e.pagesByContext.map(
|
|
2799
|
-
({ contextInfo: a, pages: i }) => `${a.name} (${a.browserInfo.name}) (${a.browserInfo.browserType}): ${i.map((u) => u.name).join(", ")}`
|
|
2800
|
-
).join(`
|
|
2801
|
-
`), n;
|
|
2802
|
-
}
|
|
2803
|
-
);
|
|
2804
|
-
}
|
|
2805
|
-
const Ze = h.object({
|
|
2806
|
-
names: h.array(h.string()).optional().describe("Names of pages to close. If not specified, closes all pages"),
|
|
2807
|
-
contextName: h.string().optional().describe(
|
|
2808
|
-
"Name of context to close pages from. If not specified, searches all contexts"
|
|
2809
|
-
),
|
|
2810
|
-
browserName: h.string().optional().describe(
|
|
2811
|
-
"Name of browser to search in. If not specified, searches all browsers"
|
|
2812
|
-
)
|
|
2813
|
-
});
|
|
2814
|
-
async function Fr(t, r, s) {
|
|
2815
|
-
let o;
|
|
2816
|
-
try {
|
|
2817
|
-
o = Ze.parse(t);
|
|
2818
|
-
} catch (f) {
|
|
2819
|
-
return {
|
|
2820
|
-
error: C(f)
|
|
2821
|
-
};
|
|
2822
|
-
}
|
|
2823
|
-
const { names: e, contextName: n, browserName: a } = o;
|
|
2824
|
-
if (!s.sessionId)
|
|
2825
|
-
return {
|
|
2826
|
-
error: "Session ID is required"
|
|
2827
|
-
};
|
|
2828
|
-
const i = D(s.sessionId), u = [], c = [];
|
|
2829
|
-
let l = [];
|
|
2830
|
-
if (a) {
|
|
2831
|
-
const f = i.browsers.get(a);
|
|
2832
|
-
if (!f)
|
|
2833
|
-
return {
|
|
2834
|
-
error: `Browser "${a}" not found`
|
|
2835
|
-
};
|
|
2836
|
-
if (n) {
|
|
2837
|
-
const d = f.contexts.get(n);
|
|
2838
|
-
if (!d)
|
|
2839
|
-
return {
|
|
2840
|
-
error: `Context "${n}" not found in browser "${f.name}" (${f.browserType})`
|
|
2841
|
-
};
|
|
2842
|
-
e ? e.forEach((m) => {
|
|
2843
|
-
const g = d.pages.get(m);
|
|
2844
|
-
g ? l.push(g) : c.push(
|
|
2845
|
-
`Page "${m}" not found in context "${d.name}" in browser "${f.name}" (${f.browserType})`
|
|
2846
|
-
);
|
|
2847
|
-
}) : l = Array.from(d.pages.values());
|
|
2848
|
-
} else
|
|
2849
|
-
for (const d of f.contexts.values())
|
|
2850
|
-
e ? e.forEach((m) => {
|
|
2851
|
-
const g = d.pages.get(m);
|
|
2852
|
-
g ? l.push(g) : c.push(
|
|
2853
|
-
`Page "${m}" not found in context "${d.name}" in browser "${f.name}" (${f.browserType})`
|
|
2854
|
-
);
|
|
2855
|
-
}) : l.push(...Array.from(d.pages.values()));
|
|
2856
|
-
} else if (n)
|
|
2857
|
-
for (const f of i.browsers.values()) {
|
|
2858
|
-
const d = f.contexts.get(n);
|
|
2859
|
-
d && (e ? e.forEach((m) => {
|
|
2860
|
-
const g = d.pages.get(m);
|
|
2861
|
-
g ? l.push(g) : c.push(
|
|
2862
|
-
`Page "${m}" not found in context "${d.name}" in browser "${f.name}" (${f.browserType})`
|
|
2863
|
-
);
|
|
2864
|
-
}) : l.push(...Array.from(d.pages.values())));
|
|
2865
|
-
}
|
|
2866
|
-
else
|
|
2867
|
-
for (const f of i.browsers.values())
|
|
2868
|
-
for (const d of f.contexts.values())
|
|
2869
|
-
e ? e.forEach((m) => {
|
|
2870
|
-
const g = d.pages.get(m);
|
|
2871
|
-
g ? l.push(g) : c.push(
|
|
2872
|
-
`Page "${m}" not found in context "${d.name}" in browser "${f.name}" (${f.browserType})`
|
|
2873
|
-
);
|
|
2874
|
-
}) : l.push(...Array.from(d.pages.values()));
|
|
2875
|
-
return await Promise.all(
|
|
2876
|
-
l.map(async (f) => {
|
|
2877
|
-
try {
|
|
2878
|
-
await f.page.close(), f.contextInfo.pages.delete(f.name), u.push(
|
|
2879
|
-
`${f.name} (${f.contextInfo.name}) (${f.contextInfo.browserInfo.name}) (${f.contextInfo.browserInfo.browserType})`
|
|
2880
|
-
);
|
|
2881
|
-
} catch (d) {
|
|
2882
|
-
c.push(
|
|
2883
|
-
`Failed to close page "${f.name}" (${f.contextInfo.name}) (${f.contextInfo.browserInfo.name}) (${f.contextInfo.browserInfo.browserType}): ${d instanceof Error ? d.message : "Unknown error"}`
|
|
2884
|
-
);
|
|
2885
|
-
}
|
|
2886
|
-
})
|
|
2887
|
-
), {
|
|
2888
|
-
closedPages: u,
|
|
2889
|
-
...c.length > 0 && { errors: c }
|
|
2890
|
-
};
|
|
2891
|
-
}
|
|
2892
|
-
function Br(t, r) {
|
|
2893
|
-
t(
|
|
2894
|
-
"playwright-page-close",
|
|
2895
|
-
{
|
|
2896
|
-
title: "Close Pages",
|
|
2897
|
-
description: "Close pages",
|
|
2898
|
-
inputSchema: Ze.shape
|
|
2899
|
-
},
|
|
2900
|
-
async (s, o) => {
|
|
2901
|
-
const e = await Fr(s, r, o);
|
|
2902
|
-
if ("error" in e)
|
|
2903
|
-
return `Method: playwright-page-close(${JSON.stringify(s)})
|
|
2904
|
-
❌ Error: ${e.error}`;
|
|
2905
|
-
const n = [];
|
|
2906
|
-
return e.closedPages.length > 0 && n.push(`✅ Closed pages: ${e.closedPages.join(", ")}`), e.errors && e.errors.length > 0 && (n.length > 0 && n.push(""), n.push("❌ Errors:"), e.errors.forEach((a) => n.push(a))), n.length === 0 && n.push("No pages to close"), `Method: playwright-page-close(${JSON.stringify(s)})
|
|
2907
|
-
${n.join(`
|
|
2908
|
-
`)}`;
|
|
2909
|
-
}
|
|
2910
|
-
);
|
|
2911
|
-
}
|
|
2912
|
-
const Xe = h.object({
|
|
2913
|
-
pageName: h.string().optional().describe("Name of previously created page to navigate"),
|
|
2914
|
-
page: re.optional().describe(
|
|
2915
|
-
"Page creation options JSON to automatically create page"
|
|
2916
|
-
),
|
|
2917
|
-
url: h.string().describe("URL to navigate to"),
|
|
2918
|
-
timeout: h.number().describe("Timeout in seconds"),
|
|
2919
|
-
waitUntil: h.enum(["load", "domcontentloaded", "networkidle", "commit"]).describe(
|
|
2920
|
-
`Wait until event:
|
|
2921
|
-
- 'domcontentloaded': DOMContentLoaded event is fired
|
|
2922
|
-
- 'load': load event is fired
|
|
2923
|
-
- 'networkidle': DISCOURAGED - no network activity for 500ms
|
|
2924
|
-
- 'commit': network response received and document started loading`
|
|
2925
|
-
)
|
|
2926
|
-
});
|
|
2927
|
-
async function Or(t, r, s) {
|
|
2928
|
-
let o;
|
|
2929
|
-
try {
|
|
2930
|
-
o = Xe.parse(t);
|
|
2931
|
-
} catch (g) {
|
|
2932
|
-
return {
|
|
2933
|
-
error: C(g)
|
|
2934
|
-
};
|
|
2935
|
-
}
|
|
2936
|
-
const { pageName: e, page: n, url: a, timeout: i, waitUntil: u } = o;
|
|
2937
|
-
if (!s.sessionId)
|
|
2938
|
-
return {
|
|
2939
|
-
error: "Session ID is required"
|
|
2940
|
-
};
|
|
2941
|
-
const c = D(s.sessionId);
|
|
2942
|
-
if (e && n)
|
|
2943
|
-
return {
|
|
2944
|
-
error: "Either pageName or page must be provided, not both"
|
|
2945
|
-
};
|
|
2946
|
-
let l = !1, f = !1, d = !1, m;
|
|
2947
|
-
if (e) {
|
|
2948
|
-
for (const g of c.browsers.values()) {
|
|
2949
|
-
for (const p of g.contexts.values())
|
|
2950
|
-
if (p.pages.has(e)) {
|
|
2951
|
-
m = p.pages.get(e);
|
|
2952
|
-
break;
|
|
2953
|
-
}
|
|
2954
|
-
if (m) break;
|
|
2955
|
-
}
|
|
2956
|
-
if (!m)
|
|
2957
|
-
return {
|
|
2958
|
-
error: `Page "${e}" not found`
|
|
2959
|
-
};
|
|
2960
|
-
} else if (n) {
|
|
2961
|
-
const g = await Ye(n, r, s);
|
|
2962
|
-
if (g.error != null)
|
|
2963
|
-
return {
|
|
2964
|
-
error: g.error
|
|
2965
|
-
};
|
|
2966
|
-
m = g.pageInfo, l = g.browserInfoCreated, f = g.contextInfoCreated, d = !0;
|
|
2967
|
-
} else
|
|
2968
|
-
return {
|
|
2969
|
-
error: "Either pageName or page must be provided"
|
|
2970
|
-
};
|
|
2971
|
-
try {
|
|
2972
|
-
const g = await m.page.goto(a, {
|
|
2973
|
-
timeout: i * 1e3,
|
|
2974
|
-
waitUntil: u
|
|
2975
|
-
});
|
|
2976
|
-
return g ? {
|
|
2977
|
-
browserInfoCreated: l,
|
|
2978
|
-
contextInfoCreated: f,
|
|
2979
|
-
pageInfoCreated: d,
|
|
2980
|
-
pageInfo: m,
|
|
2981
|
-
status: g.status()
|
|
2982
|
-
} : {
|
|
2983
|
-
browserInfoCreated: l,
|
|
2984
|
-
contextInfoCreated: f,
|
|
2985
|
-
pageInfoCreated: d,
|
|
2986
|
-
pageInfo: m,
|
|
2987
|
-
status: 200
|
|
2988
|
-
};
|
|
2989
|
-
} catch (g) {
|
|
2990
|
-
return {
|
|
2991
|
-
error: `Failed to navigate to "${a}": ${g instanceof Error ? g.message : "Unknown error"}`
|
|
2992
|
-
};
|
|
2993
|
-
}
|
|
2994
|
-
}
|
|
2995
|
-
function Rr(t, r) {
|
|
2996
|
-
t(
|
|
2997
|
-
"playwright-page-goto",
|
|
2998
|
-
{
|
|
2999
|
-
title: "Navigate Page",
|
|
3000
|
-
description: "Navigate page to URL. Use for manual browser interaction",
|
|
3001
|
-
inputSchema: Xe.shape
|
|
3002
|
-
},
|
|
3003
|
-
async (s, o) => {
|
|
3004
|
-
const e = await Or(s, r, o);
|
|
3005
|
-
if (e.error != null)
|
|
3006
|
-
return `Method: playwright-page-goto(${JSON.stringify(s)})
|
|
3007
|
-
❌ Error: ${e.error}`;
|
|
3008
|
-
let n = `Method: playwright-page-goto(${JSON.stringify(s)})
|
|
3009
|
-
`;
|
|
3010
|
-
return e.browserInfoCreated && (n += `✅ Browser "${e.pageInfo.contextInfo.browserInfo.name}" (${e.pageInfo.contextInfo.browserInfo.browserType}) created successfully
|
|
3011
|
-
`), e.contextInfoCreated && (n += `✅ Context "${e.pageInfo.contextInfo.name}" created successfully in browser "${e.pageInfo.contextInfo.browserInfo.name}" (${e.pageInfo.contextInfo.browserInfo.browserType})
|
|
3012
|
-
`), e.pageInfoCreated && (n += `✅ Page "${e.pageInfo.name}" created successfully in context "${e.pageInfo.contextInfo.name}" in browser "${e.pageInfo.contextInfo.browserInfo.name}" (${e.pageInfo.contextInfo.browserInfo.browserType})
|
|
3013
|
-
`), n += `✅ Navigation completed with HTTP status: ${e.status}`, n;
|
|
3014
|
-
}
|
|
3015
|
-
);
|
|
3016
|
-
}
|
|
3017
|
-
const se = h.object({
|
|
3018
|
-
name: h.string().describe(
|
|
3019
|
-
"Unique name for the DOM snapshot query. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
3020
|
-
),
|
|
3021
|
-
cssSelector: h.string().describe("CSS selector to capture page content")
|
|
3022
|
-
});
|
|
3023
|
-
async function et(t, r, s) {
|
|
3024
|
-
let o;
|
|
3025
|
-
try {
|
|
3026
|
-
o = se.parse(t);
|
|
3027
|
-
} catch (u) {
|
|
3028
|
-
return {
|
|
3029
|
-
error: C(u)
|
|
3030
|
-
};
|
|
3031
|
-
}
|
|
3032
|
-
const { name: e, cssSelector: n } = o;
|
|
3033
|
-
if (!s.sessionId)
|
|
3034
|
-
return {
|
|
3035
|
-
error: "Session ID is required"
|
|
3036
|
-
};
|
|
3037
|
-
const a = D(s.sessionId);
|
|
3038
|
-
if (a.domSnapshotQueries.has(e))
|
|
3039
|
-
return {
|
|
3040
|
-
error: `DOM snapshot query "${e}" already exists`
|
|
3041
|
-
};
|
|
3042
|
-
const i = {
|
|
3043
|
-
name: e,
|
|
3044
|
-
cssSelector: n
|
|
3045
|
-
};
|
|
3046
|
-
return a.domSnapshotQueries.set(e, i), {
|
|
3047
|
-
snapshotQuery: i
|
|
3048
|
-
};
|
|
3049
|
-
}
|
|
3050
|
-
function Pr(t, r) {
|
|
3051
|
-
t(
|
|
3052
|
-
"playwright-dom-snapshot-query-create",
|
|
3053
|
-
{
|
|
3054
|
-
title: "Create DOM Snapshot Query",
|
|
3055
|
-
description: "Create a DOM snapshot query. Prefer dom-snapshot-browse if you need to immediately create a query and snapshot and browse it",
|
|
3056
|
-
inputSchema: se.shape
|
|
3057
|
-
},
|
|
3058
|
-
async (s, o) => {
|
|
3059
|
-
const e = await et(s, r, o);
|
|
3060
|
-
return e.error != null ? `Method: playwright-dom-snapshot-query-create(${JSON.stringify(s)})
|
|
3061
|
-
❌ Error: ${e.error}` : `Method: playwright-dom-snapshot-query-create(${JSON.stringify(s)})
|
|
3062
|
-
✅ DOM snapshot query "${e.snapshotQuery.name}" created successfully`;
|
|
3063
|
-
}
|
|
3064
|
-
);
|
|
3065
|
-
}
|
|
3066
|
-
function zr(t) {
|
|
3067
|
-
return function(s, o) {
|
|
3068
|
-
let e, n = 0;
|
|
3069
|
-
const a = o ? o.length : 0;
|
|
3070
|
-
let i = 1, u = 0, c = 0, l, f;
|
|
3071
|
-
if (o)
|
|
3072
|
-
for (let g = 0; g < o.length; g++) {
|
|
3073
|
-
const p = o[g];
|
|
3074
|
-
n += p.countMatched, i += p.countTotal, u += p.tokens, c += p.tokensTotal;
|
|
3075
|
-
}
|
|
3076
|
-
s ? (l = s.uid, f = s.tagName, e = s.isMatched, e && (n += 1)) : (l = null, f = null, e = !1);
|
|
3077
|
-
let d;
|
|
3078
|
-
f ? d = {
|
|
3079
|
-
indent: !0,
|
|
3080
|
-
textOpen: `<${f} uid:${l}>`,
|
|
3081
|
-
textClose: `</${f}>`
|
|
3082
|
-
} : d = {
|
|
3083
|
-
indent: !0,
|
|
3084
|
-
textOpen: `<root uid:${l}>`,
|
|
3085
|
-
textClose: "</root>"
|
|
3086
|
-
};
|
|
3087
|
-
const m = Ue(d);
|
|
3088
|
-
return c += m, {
|
|
3089
|
-
uid: l,
|
|
3090
|
-
tagName: f,
|
|
3091
|
-
isMatched: e,
|
|
3092
|
-
countMatched: n,
|
|
3093
|
-
countChilds: a,
|
|
3094
|
-
countTotal: i,
|
|
3095
|
-
tokens: m,
|
|
3096
|
-
tokensChilds: u,
|
|
3097
|
-
tokensTotal: c,
|
|
3098
|
-
text: d
|
|
3099
|
-
};
|
|
3100
|
-
};
|
|
3101
|
-
}
|
|
3102
|
-
function Lr(t, r) {
|
|
3103
|
-
const s = j(r), o = s.getChilds(s.root), e = Le({
|
|
3104
|
-
getId: (n) => {
|
|
3105
|
-
const a = s.getId(n);
|
|
3106
|
-
if (a == null)
|
|
3107
|
-
throw new Error(
|
|
3108
|
-
`Invalid tree structure: node ID is null for node ${JSON.stringify(n)}`
|
|
3109
|
-
);
|
|
3110
|
-
return a;
|
|
3111
|
-
},
|
|
3112
|
-
getChilds: (n) => s.getChilds(n),
|
|
3113
|
-
createSnapshotNode: zr(),
|
|
3114
|
-
rootNodes: o ?? []
|
|
3115
|
-
});
|
|
3116
|
-
return j(e);
|
|
3117
|
-
}
|
|
3118
|
-
const oe = h.object({
|
|
3119
|
-
pageName: h.string().describe("Name of previously created page, to create snapshot from"),
|
|
3120
|
-
queryName: h.string().optional().describe("Name of previously created DOM snapshot query, to use"),
|
|
3121
|
-
query: se.optional().describe(
|
|
3122
|
-
"DOM snapshot query creation options JSON to automatically create query"
|
|
3123
|
-
),
|
|
3124
|
-
name: h.string().describe(
|
|
3125
|
-
"Unique name for the DOM snapshot. Recommended format: kebab-case-1, kebab-case-2, ..."
|
|
3126
|
-
)
|
|
3127
|
-
});
|
|
3128
|
-
async function tt(t, r, s) {
|
|
3129
|
-
let o;
|
|
3130
|
-
try {
|
|
3131
|
-
o = oe.parse(t);
|
|
3132
|
-
} catch (d) {
|
|
3133
|
-
return {
|
|
3134
|
-
error: C(d)
|
|
3135
|
-
};
|
|
3136
|
-
}
|
|
3137
|
-
const { pageName: e, queryName: n, query: a, name: i } = o;
|
|
3138
|
-
if (!s.sessionId)
|
|
3139
|
-
return {
|
|
3140
|
-
error: "Session ID is required"
|
|
3141
|
-
};
|
|
3142
|
-
const u = D(s.sessionId);
|
|
3143
|
-
let c;
|
|
3144
|
-
for (const d of u.browsers.values()) {
|
|
3145
|
-
for (const m of d.contexts.values())
|
|
3146
|
-
if (m.pages.has(e)) {
|
|
3147
|
-
c = m.pages.get(e);
|
|
3148
|
-
break;
|
|
3149
|
-
}
|
|
3150
|
-
if (c) break;
|
|
3151
|
-
}
|
|
3152
|
-
if (!c)
|
|
3153
|
-
return {
|
|
3154
|
-
error: `Page "${e}" not found`
|
|
3155
|
-
};
|
|
3156
|
-
if (c.domSnapshots.has(i))
|
|
3157
|
-
return {
|
|
3158
|
-
error: `DOM snapshot "${i}" already exists in page "${e}"`
|
|
3159
|
-
};
|
|
3160
|
-
if (n && a)
|
|
3161
|
-
return {
|
|
3162
|
-
error: "Either queryName or query must be provided, not both"
|
|
3163
|
-
};
|
|
3164
|
-
let l, f = !1;
|
|
3165
|
-
if (n) {
|
|
3166
|
-
const d = u.domSnapshotQueries.get(n);
|
|
3167
|
-
if (!d)
|
|
3168
|
-
return {
|
|
3169
|
-
error: `DOM snapshot query "${n}" not found`
|
|
3170
|
-
};
|
|
3171
|
-
l = d;
|
|
3172
|
-
} else if (a) {
|
|
3173
|
-
const d = await et(
|
|
3174
|
-
a,
|
|
3175
|
-
r,
|
|
3176
|
-
s
|
|
3177
|
-
);
|
|
3178
|
-
if (d.error != null)
|
|
3179
|
-
return {
|
|
3180
|
-
error: d.error
|
|
3181
|
-
};
|
|
3182
|
-
l = d.snapshotQuery, f = !0;
|
|
3183
|
-
} else
|
|
3184
|
-
return {
|
|
3185
|
-
error: "Either queryName or query must be provided"
|
|
3186
|
-
};
|
|
3187
|
-
try {
|
|
3188
|
-
const d = await c.page.evaluate(
|
|
3189
|
-
(y) => {
|
|
3190
|
-
const w = window.__mcp_playwright_tool_tx4byhar35_createDomSnapshotTreeRawDom;
|
|
3191
|
-
if (!w)
|
|
3192
|
-
throw new Error("DOM snapshot global function not initialized");
|
|
3193
|
-
const S = w(y);
|
|
3194
|
-
return {
|
|
3195
|
-
idToNode: Array.from(S.idToNode.entries()),
|
|
3196
|
-
idToChildIds: Array.from(S.idToChildIds.entries())
|
|
3197
|
-
};
|
|
3198
|
-
},
|
|
3199
|
-
l
|
|
3200
|
-
), m = {
|
|
3201
|
-
idToNode: new Map(d.idToNode),
|
|
3202
|
-
idToChildIds: new Map(d.idToChildIds)
|
|
3203
|
-
}, g = Lr(l, m), p = {
|
|
3204
|
-
name: i,
|
|
3205
|
-
query: l,
|
|
3206
|
-
tree: g
|
|
3207
|
-
};
|
|
3208
|
-
return c.domSnapshots.set(i, p), {
|
|
3209
|
-
domSnapshot: p,
|
|
3210
|
-
queryCreated: f
|
|
3211
|
-
};
|
|
3212
|
-
} catch (d) {
|
|
3213
|
-
return {
|
|
3214
|
-
error: `Failed to create DOM snapshot: ${d instanceof Error ? d.message : "Unknown error"}`
|
|
3215
|
-
};
|
|
3216
|
-
}
|
|
3217
|
-
}
|
|
3218
|
-
function Ur(t, r) {
|
|
3219
|
-
t(
|
|
3220
|
-
"playwright-dom-snapshot-create",
|
|
3221
|
-
{
|
|
3222
|
-
title: "Create DOM Snapshot",
|
|
3223
|
-
description: "Create a DOM snapshot of page. Use this to capture webpage state for later browsing. Prefer dom-snapshot-browse if you need to immediately create and browse a snapshot",
|
|
3224
|
-
inputSchema: oe.shape
|
|
3225
|
-
},
|
|
3226
|
-
async (s, o) => {
|
|
3227
|
-
const e = await tt(s, r, o);
|
|
3228
|
-
if (e.error != null)
|
|
3229
|
-
return `Method: playwright-dom-snapshot-create(${JSON.stringify(s)})
|
|
3230
|
-
❌ Error: ${e.error}`;
|
|
3231
|
-
let n = `Method: playwright-dom-snapshot-create(${JSON.stringify(s)})
|
|
3232
|
-
`;
|
|
3233
|
-
return e.queryCreated && (n += `✅ DOM snapshot query "${e.domSnapshot.query.name}" created successfully
|
|
3234
|
-
`), n += `✅ DOM snapshot "${e.domSnapshot.name}" created successfully`, n;
|
|
3235
|
-
}
|
|
3236
|
-
);
|
|
3237
|
-
}
|
|
3238
|
-
class Ar {
|
|
3239
|
-
tokens = 16;
|
|
3240
|
-
getReportText = (r) => ({
|
|
3241
|
-
indent: !0,
|
|
3242
|
-
textOpen: `[${r.indexRange[0]}-${r.indexRange[1]}] ${r.countMatched} matched ${r.tokensGrouped} tokens`,
|
|
3243
|
-
textClose: null
|
|
3244
|
-
});
|
|
3245
|
-
add = (r, s, o) => r == null ? {
|
|
3246
|
-
indexRange: [o, o],
|
|
3247
|
-
countGrouped: 1,
|
|
3248
|
-
countMatched: s.countMatched,
|
|
3249
|
-
tokensGrouped: s.tokens
|
|
3250
|
-
} : (r.indexRange[1] = o, r.countGrouped += 1, r.countMatched += s.countMatched, r.tokensGrouped += s.tokens, r);
|
|
3251
|
-
}
|
|
3252
|
-
const rt = h.object({
|
|
3253
|
-
snapshotName: h.string().optional().describe("Name of previously created DOM snapshot, to use"),
|
|
3254
|
-
snapshot: oe.optional().describe(
|
|
3255
|
-
"DOM snapshot creation options JSON to automatically create snapshot"
|
|
3256
|
-
),
|
|
3257
|
-
parentUid: h.number().optional().describe("UID of parent node to browse. Omit to browse the root node"),
|
|
3258
|
-
childsIndexRange: h.tuple([h.number(), h.number()]).optional().describe(
|
|
3259
|
-
"Child index range to show [start, end]. Only use the exact ranges that appeared in previous snapshot results - do not modify, combine, or split them"
|
|
3260
|
-
)
|
|
3261
|
-
// maxCountTotal: z
|
|
3262
|
-
// .number()
|
|
3263
|
-
// .default(100)
|
|
3264
|
-
// .describe('Maximum total number of items to show'),
|
|
3265
|
-
// maxTokensTotal: z
|
|
3266
|
-
// .number()
|
|
3267
|
-
// .default(10000)
|
|
3268
|
-
// .describe('Maximum total tokens to show'),
|
|
3269
|
-
// maxCountGroup: z.number().default(10).describe('Maximum items per group'),
|
|
3270
|
-
// maxTokensGroup: z.number().default(1000).describe('Maximum tokens per group'),
|
|
3271
|
-
});
|
|
3272
|
-
async function qr(t, r, s) {
|
|
3273
|
-
let o;
|
|
3274
|
-
try {
|
|
3275
|
-
o = rt.parse(t);
|
|
3276
|
-
} catch (p) {
|
|
3277
|
-
return {
|
|
3278
|
-
error: C(p)
|
|
3279
|
-
};
|
|
3280
|
-
}
|
|
3281
|
-
const {
|
|
3282
|
-
snapshotName: e,
|
|
3283
|
-
snapshot: n,
|
|
3284
|
-
childsIndexRange: a
|
|
3285
|
-
// maxCountTotal,
|
|
3286
|
-
// maxTokensTotal,
|
|
3287
|
-
// maxCountGroup,
|
|
3288
|
-
// maxTokensGroup,
|
|
3289
|
-
} = o, i = 60, u = 1e3, c = 25, l = 900;
|
|
3290
|
-
if (!s.sessionId)
|
|
3291
|
-
return {
|
|
3292
|
-
error: "Session ID is required"
|
|
3293
|
-
};
|
|
3294
|
-
const f = D(s.sessionId);
|
|
3295
|
-
if (e && n)
|
|
3296
|
-
return {
|
|
3297
|
-
error: "Either snapshotName or snapshot must be provided, not both"
|
|
3298
|
-
};
|
|
3299
|
-
let d, m = !1, g = !1;
|
|
3300
|
-
if (e) {
|
|
3301
|
-
for (const p of f.browsers.values()) {
|
|
3302
|
-
for (const y of p.contexts.values()) {
|
|
3303
|
-
for (const w of y.pages.values())
|
|
3304
|
-
if (w.domSnapshots.has(e)) {
|
|
3305
|
-
d = w.domSnapshots.get(e);
|
|
3306
|
-
break;
|
|
3307
|
-
}
|
|
3308
|
-
if (d != null) break;
|
|
3309
|
-
}
|
|
3310
|
-
if (d != null) break;
|
|
3311
|
-
}
|
|
3312
|
-
if (d == null)
|
|
3313
|
-
return {
|
|
3314
|
-
error: `DOM snapshot "${e}" not found`
|
|
3315
|
-
};
|
|
3316
|
-
} else if (n) {
|
|
3317
|
-
const p = await tt(
|
|
3318
|
-
n,
|
|
3319
|
-
r,
|
|
3320
|
-
s
|
|
3321
|
-
);
|
|
3322
|
-
if (p.error != null)
|
|
3323
|
-
return {
|
|
3324
|
-
error: p.error
|
|
3325
|
-
};
|
|
3326
|
-
d = p.domSnapshot, m = p.queryCreated, g = !0;
|
|
3327
|
-
} else
|
|
3328
|
-
return {
|
|
3329
|
-
error: "Either snapshotName or snapshot must be provided"
|
|
3330
|
-
};
|
|
3331
|
-
try {
|
|
3332
|
-
const p = o.parentUid, y = qe({
|
|
3333
|
-
tree: d.tree,
|
|
3334
|
-
request: {
|
|
3335
|
-
parentNodeId: p,
|
|
3336
|
-
childsIndexRange: a,
|
|
3337
|
-
limits: {
|
|
3338
|
-
maxCountTotal: i,
|
|
3339
|
-
maxTokensTotal: u,
|
|
3340
|
-
maxCountGroup: c,
|
|
3341
|
-
maxTokensGroup: l
|
|
3342
|
-
}
|
|
3343
|
-
},
|
|
3344
|
-
indexRangeGroupStrategy: new Ar()
|
|
3345
|
-
}), w = Ge(y);
|
|
3346
|
-
return {
|
|
3347
|
-
domSnapshot: d,
|
|
3348
|
-
queryCreated: m,
|
|
3349
|
-
snapshotCreated: g,
|
|
3350
|
-
parentUid: p,
|
|
3351
|
-
childsIndexRange: a,
|
|
3352
|
-
report: w
|
|
3353
|
-
};
|
|
3354
|
-
} catch (p) {
|
|
3355
|
-
return {
|
|
3356
|
-
error: `Failed to browse DOM snapshot: ${p instanceof Error ? p.message : "Unknown error"}`
|
|
3357
|
-
};
|
|
3358
|
-
}
|
|
3359
|
-
}
|
|
3360
|
-
function Gr(t, r) {
|
|
3361
|
-
t(
|
|
3362
|
-
"playwright-dom-snapshot-browse",
|
|
3363
|
-
{
|
|
3364
|
-
title: "Browse DOM Snapshot",
|
|
3365
|
-
description: "Browse and explore DOM. Use this to browse, analyze, explore, inspect, etc webpage structure and styles, find elements, or inspect page content",
|
|
3366
|
-
inputSchema: rt.shape
|
|
3367
|
-
},
|
|
3368
|
-
async (s, o) => {
|
|
3369
|
-
const e = await qr(s, r, o);
|
|
3370
|
-
if (e.error != null)
|
|
3371
|
-
return `Method: playwright-dom-snapshot-browse(${JSON.stringify(s)})
|
|
3372
|
-
❌ Error: ${e.error}`;
|
|
3373
|
-
let n = `Method: playwright-dom-snapshot-browse(${JSON.stringify(s)})
|
|
3374
|
-
`;
|
|
3375
|
-
if (e.queryCreated && (n += `✅ DOM snapshot query "${e.domSnapshot.query.name}" created successfully
|
|
3376
|
-
`), e.snapshotCreated && (n += `✅ DOM snapshot "${e.domSnapshot.name}" created successfully
|
|
3377
|
-
`), n += `✅ Browsing DOM snapshot "${e.domSnapshot.name}":
|
|
3378
|
-
`, n += `CSS Selector: ${e.domSnapshot.query.cssSelector}
|
|
3379
|
-
`, n += `Parent UID: ${e.parentUid ?? "null (root node)"}
|
|
3380
|
-
`, e.childsIndexRange) {
|
|
3381
|
-
const [a, i] = e.childsIndexRange, c = (e.parentUid ? e.domSnapshot.tree.getNode(e.parentUid) : e.domSnapshot.tree.root).countChilds;
|
|
3382
|
-
n += ` Showing indexes: ${a}-${i} of ${c}
|
|
3383
|
-
`;
|
|
3384
|
-
}
|
|
3385
|
-
return n += `
|
|
3386
|
-
${e.report}`, n;
|
|
3387
|
-
}
|
|
3388
|
-
);
|
|
3389
|
-
}
|
|
3390
|
-
function jr(t, r) {
|
|
3391
|
-
r.browserCreate && wr(t, r), r.browserList && br(t, r), r.browserClose && xr(t, r), r.contextCreate && $r(t, r), r.contextList && Mr(t, r), r.contextClose && vr(t, r), r.pageCreate && Nr(t, r), r.pageList && Dr(t, r), r.pageClose && Br(t, r), r.pageGoto && Rr(t, r), r.domSnapshotQueryCreate && Pr(t, r), r.domSnapshotCreate && Ur(t, r), r.domSnapshotBrowse && Gr(t, r), console.log("Playwright manager");
|
|
3392
|
-
}
|
|
3393
|
-
function _r(t) {
|
|
3394
|
-
const { logFilePath: r } = t;
|
|
3395
|
-
return async function(o, e, n, a) {
|
|
3396
|
-
await q({
|
|
3397
|
-
logFilePath: r,
|
|
3398
|
-
message: "ERROR",
|
|
3399
|
-
data: {
|
|
3400
|
-
request: {
|
|
3401
|
-
url: e.url,
|
|
3402
|
-
method: e.method,
|
|
3403
|
-
headers: e.headers,
|
|
3404
|
-
body: e.body
|
|
3405
|
-
},
|
|
3406
|
-
error: o.message,
|
|
3407
|
-
stack: o.stack
|
|
3408
|
-
}
|
|
3409
|
-
}), n.status(500).send({
|
|
3410
|
-
error: "Internal Server Error",
|
|
3411
|
-
message: o.stack || o.message || o.toString()
|
|
3412
|
-
});
|
|
3413
|
-
};
|
|
3414
|
-
}
|
|
3415
|
-
function st() {
|
|
3416
|
-
return `mcp_${(/* @__PURE__ */ new Date()).toISOString().substring(0, 19).replace(/T/, "_").replace(/:/g, "-")}.log`;
|
|
3417
|
-
}
|
|
3418
|
-
function Jr(t) {
|
|
3419
|
-
const r = A(), s = Kr();
|
|
3420
|
-
return r.use(s), r;
|
|
3421
|
-
}
|
|
3422
|
-
function Kr(t) {
|
|
3423
|
-
const r = A.Router();
|
|
3424
|
-
return r.use((s, o, e) => {
|
|
3425
|
-
s.method === "OPTIONS" ? o.status(403).send("CORS forbidden") : e();
|
|
3426
|
-
}), r.use(A.json()), r;
|
|
3427
|
-
}
|
|
3428
|
-
function Wr(t) {
|
|
3429
|
-
const r = A.Router();
|
|
3430
|
-
return r.use(wt({ authToken: t.authToken })), r.all("/mcp", $t(t)), r;
|
|
3431
|
-
}
|
|
3432
|
-
function Qr(t, r) {
|
|
3433
|
-
return t.use(_r({ logFilePath: r.logFilePath })), new Promise((s, o) => {
|
|
3434
|
-
let e;
|
|
3435
|
-
const n = () => {
|
|
3436
|
-
s(e);
|
|
3437
|
-
};
|
|
3438
|
-
try {
|
|
3439
|
-
e = r.host ? t.listen(r.port ?? 0, r.host, n) : t.listen(r.port ?? 0, n), e.addListener("error", (a) => {
|
|
3440
|
-
o(a);
|
|
3441
|
-
});
|
|
3442
|
-
} catch (a) {
|
|
3443
|
-
o(a);
|
|
3444
|
-
}
|
|
3445
|
-
});
|
|
3446
|
-
}
|
|
3447
|
-
function Hr(t, r) {
|
|
3448
|
-
if (!t.address())
|
|
3449
|
-
throw new Error("Server address is not available. Check your DNS and host configuration.");
|
|
3450
|
-
const o = t.address().family, e = t.address().port;
|
|
3451
|
-
let n = t.address().address;
|
|
3452
|
-
n === "::" ? n = "localhost" : o === "IPv6" && (n = `[${n}]`);
|
|
3453
|
-
const a = `http://${o === "IPv6" ? `[${n}]` : n}:${e}`;
|
|
3454
|
-
return `Project Tools - MCP Server Started
|
|
3455
|
-
|
|
3456
|
-
Server Name: ${r.name}
|
|
3457
|
-
Server Version: ${r.version}
|
|
3458
|
-
Server URL: ${a}/mcp
|
|
3459
|
-
SSE Endpoint: ${a}/sse
|
|
3460
|
-
|
|
3461
|
-
Log File: ${T.resolve(r.logFilePath)}`;
|
|
3462
|
-
}
|
|
3463
|
-
function Yr(t, r) {
|
|
3464
|
-
const s = T.join(r.logDir, st()), o = At(t, {
|
|
3465
|
-
logFilePath: s
|
|
3466
|
-
});
|
|
3467
|
-
r.tools.processManager && Ut(o, r.tools.processManager), r.tools.fsManager && gr(o, r.tools.fsManager), r.tools.playwrightManager && jr(o, {
|
|
3468
|
-
...r.tools.playwrightManager
|
|
3469
|
-
});
|
|
3470
|
-
}
|
|
3471
|
-
async function ps(t) {
|
|
3472
|
-
const r = T.join(t.logDir, st()), s = Jr(), o = Wr({
|
|
3473
|
-
...t,
|
|
3474
|
-
logFilePath: r,
|
|
3475
|
-
createMcpServer: () => {
|
|
3476
|
-
const n = new ot({
|
|
3477
|
-
title: t.title,
|
|
3478
|
-
name: t.name,
|
|
3479
|
-
version: t.version
|
|
3480
|
-
});
|
|
3481
|
-
return Yr(n, t), n;
|
|
3482
|
-
}
|
|
3483
|
-
});
|
|
3484
|
-
s.use(o);
|
|
3485
|
-
const e = await Qr(s, {
|
|
3486
|
-
host: t.host,
|
|
3487
|
-
port: t.port,
|
|
3488
|
-
logFilePath: r
|
|
3489
|
-
});
|
|
3490
|
-
return console.log(
|
|
3491
|
-
Hr(e, {
|
|
3492
|
-
title: t.title,
|
|
3493
|
-
name: t.name,
|
|
3494
|
-
version: t.version,
|
|
3495
|
-
logFilePath: r
|
|
3496
|
-
})
|
|
3497
|
-
), e;
|
|
3498
|
-
}
|
|
3499
|
-
export {
|
|
3500
|
-
hs as A,
|
|
3501
|
-
ms as S,
|
|
3502
|
-
fs as a,
|
|
3503
|
-
ds as b,
|
|
3504
|
-
Zt as p,
|
|
3505
|
-
ps as s
|
|
3506
|
-
};
|