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