@tontoko/fast-playwright-mcp 0.0.4
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/LICENSE +202 -0
- package/README.md +1047 -0
- package/cli.js +18 -0
- package/config.d.ts +124 -0
- package/index.d.ts +25 -0
- package/index.js +18 -0
- package/lib/actions.d.js +0 -0
- package/lib/batch/batch-executor.js +137 -0
- package/lib/browser-context-factory.js +252 -0
- package/lib/browser-server-backend.js +139 -0
- package/lib/config/constants.js +80 -0
- package/lib/config.js +405 -0
- package/lib/context.js +274 -0
- package/lib/diagnostics/common/diagnostic-base.js +63 -0
- package/lib/diagnostics/common/error-enrichment-utils.js +212 -0
- package/lib/diagnostics/common/index.js +56 -0
- package/lib/diagnostics/common/initialization-manager.js +210 -0
- package/lib/diagnostics/common/performance-tracker.js +132 -0
- package/lib/diagnostics/diagnostic-error.js +140 -0
- package/lib/diagnostics/diagnostic-level.js +123 -0
- package/lib/diagnostics/diagnostic-thresholds.js +347 -0
- package/lib/diagnostics/element-discovery.js +441 -0
- package/lib/diagnostics/enhanced-error-handler.js +376 -0
- package/lib/diagnostics/error-enrichment.js +157 -0
- package/lib/diagnostics/frame-reference-manager.js +179 -0
- package/lib/diagnostics/page-analyzer.js +639 -0
- package/lib/diagnostics/parallel-page-analyzer.js +129 -0
- package/lib/diagnostics/resource-manager.js +134 -0
- package/lib/diagnostics/smart-config.js +482 -0
- package/lib/diagnostics/smart-handle.js +118 -0
- package/lib/diagnostics/unified-system.js +717 -0
- package/lib/extension/cdp-relay.js +486 -0
- package/lib/extension/extension-context-factory.js +74 -0
- package/lib/extension/main.js +41 -0
- package/lib/file-utils.js +42 -0
- package/lib/generate-keys.js +75 -0
- package/lib/http-server.js +50 -0
- package/lib/in-process-client.js +64 -0
- package/lib/index.js +48 -0
- package/lib/javascript.js +90 -0
- package/lib/log.js +33 -0
- package/lib/loop/loop-claude.js +247 -0
- package/lib/loop/loop-open-ai.js +222 -0
- package/lib/loop/loop.js +174 -0
- package/lib/loop/main.js +46 -0
- package/lib/loopTools/context.js +76 -0
- package/lib/loopTools/main.js +65 -0
- package/lib/loopTools/perform.js +40 -0
- package/lib/loopTools/snapshot.js +37 -0
- package/lib/loopTools/tool.js +26 -0
- package/lib/manual-promise.js +125 -0
- package/lib/mcp/in-process-transport.js +91 -0
- package/lib/mcp/proxy-backend.js +127 -0
- package/lib/mcp/server.js +123 -0
- package/lib/mcp/transport.js +159 -0
- package/lib/package.js +28 -0
- package/lib/program.js +82 -0
- package/lib/response.js +493 -0
- package/lib/schemas/expectation.js +152 -0
- package/lib/session-log.js +210 -0
- package/lib/tab.js +417 -0
- package/lib/tools/base-tool-handler.js +141 -0
- package/lib/tools/batch-execute.js +150 -0
- package/lib/tools/common.js +65 -0
- package/lib/tools/console.js +60 -0
- package/lib/tools/diagnose/diagnose-analysis-runner.js +101 -0
- package/lib/tools/diagnose/diagnose-config-handler.js +130 -0
- package/lib/tools/diagnose/diagnose-report-builder.js +394 -0
- package/lib/tools/diagnose.js +147 -0
- package/lib/tools/dialogs.js +57 -0
- package/lib/tools/evaluate.js +67 -0
- package/lib/tools/files.js +53 -0
- package/lib/tools/find-elements.js +307 -0
- package/lib/tools/install.js +60 -0
- package/lib/tools/keyboard.js +93 -0
- package/lib/tools/mouse.js +110 -0
- package/lib/tools/navigate.js +82 -0
- package/lib/tools/network.js +50 -0
- package/lib/tools/pdf.js +46 -0
- package/lib/tools/screenshot.js +113 -0
- package/lib/tools/snapshot.js +158 -0
- package/lib/tools/tabs.js +97 -0
- package/lib/tools/tool.js +47 -0
- package/lib/tools/utils.js +131 -0
- package/lib/tools/wait.js +64 -0
- package/lib/tools.js +65 -0
- package/lib/types/batch.js +47 -0
- package/lib/types/diff.js +0 -0
- package/lib/types/performance.js +0 -0
- package/lib/types/threshold-base.js +0 -0
- package/lib/utils/array-utils.js +44 -0
- package/lib/utils/code-deduplication-utils.js +141 -0
- package/lib/utils/common-formatters.js +252 -0
- package/lib/utils/console-filter.js +64 -0
- package/lib/utils/diagnostic-report-utils.js +178 -0
- package/lib/utils/diff-formatter.js +126 -0
- package/lib/utils/disposable-manager.js +135 -0
- package/lib/utils/error-handler-middleware.js +77 -0
- package/lib/utils/image-processor.js +137 -0
- package/lib/utils/index.js +92 -0
- package/lib/utils/report-builder.js +189 -0
- package/lib/utils/request-logger.js +82 -0
- package/lib/utils/response-diff-detector.js +150 -0
- package/lib/utils/section-builder.js +62 -0
- package/lib/utils/tool-patterns.js +153 -0
- package/lib/utils.js +46 -0
- package/package.json +77 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/generate-keys.ts
|
|
21
|
+
import { generateKeyPairSync, randomBytes } from "node:crypto";
|
|
22
|
+
function generateMockKeyPair() {
|
|
23
|
+
const { privateKey: privateKeyObj, publicKey } = generateKeyPairSync("rsa", {
|
|
24
|
+
modulusLength: 2048,
|
|
25
|
+
publicKeyEncoding: {
|
|
26
|
+
type: "spki",
|
|
27
|
+
format: "pem"
|
|
28
|
+
},
|
|
29
|
+
privateKeyEncoding: {
|
|
30
|
+
type: "pkcs8",
|
|
31
|
+
format: "pem"
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const privateKey = privateKeyObj;
|
|
35
|
+
const serialNumber = randomBytes(16).toString("hex");
|
|
36
|
+
const currentDate = new Date;
|
|
37
|
+
const expiryDate = new Date(currentDate.getTime() + 365 * 24 * 60 * 60 * 1000);
|
|
38
|
+
const certificate = generateSelfSignedCert(publicKey, serialNumber, currentDate, expiryDate);
|
|
39
|
+
return {
|
|
40
|
+
privateKey,
|
|
41
|
+
certificate
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function loadOrGenerateKeys() {
|
|
45
|
+
const envPrivateKey = process.env.TEST_PRIVATE_KEY;
|
|
46
|
+
const envCertificate = process.env.TEST_CERTIFICATE;
|
|
47
|
+
if (envPrivateKey && envCertificate) {
|
|
48
|
+
return {
|
|
49
|
+
privateKey: envPrivateKey,
|
|
50
|
+
certificate: envCertificate
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return getBackupTestKeys();
|
|
54
|
+
}
|
|
55
|
+
function getBackupTestKeys() {
|
|
56
|
+
return generateMockKeyPair();
|
|
57
|
+
}
|
|
58
|
+
function generateSelfSignedCert(publicKey, serialNumber, notBefore, notAfter) {
|
|
59
|
+
const mockCert = `-----BEGIN CERTIFICATE-----
|
|
60
|
+
${Buffer.from(`
|
|
61
|
+
Mock Certificate for Testing
|
|
62
|
+
Serial: ${serialNumber}
|
|
63
|
+
Valid from: ${notBefore.toISOString()}
|
|
64
|
+
Valid to: ${notAfter.toISOString()}
|
|
65
|
+
${publicKey}
|
|
66
|
+
`).toString("base64").match(/.{1,64}/g)?.join(`
|
|
67
|
+
`) || ""}
|
|
68
|
+
-----END CERTIFICATE-----`;
|
|
69
|
+
return mockCert;
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
loadOrGenerateKeys,
|
|
73
|
+
getBackupTestKeys,
|
|
74
|
+
generateMockKeyPair
|
|
75
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/http-server.ts
|
|
21
|
+
import assert from "node:assert/strict";
|
|
22
|
+
import http from "node:http";
|
|
23
|
+
async function startHttpServer(config) {
|
|
24
|
+
const { host, port } = config;
|
|
25
|
+
const httpServer = http.createServer();
|
|
26
|
+
await new Promise((resolve, reject) => {
|
|
27
|
+
httpServer.on("error", reject);
|
|
28
|
+
httpServer.listen(port, host, () => {
|
|
29
|
+
resolve();
|
|
30
|
+
httpServer.removeListener("error", reject);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
return httpServer;
|
|
34
|
+
}
|
|
35
|
+
function httpAddressToString(address) {
|
|
36
|
+
assert(address, "Could not bind server socket");
|
|
37
|
+
if (typeof address === "string") {
|
|
38
|
+
return address;
|
|
39
|
+
}
|
|
40
|
+
const resolvedPort = address.port;
|
|
41
|
+
let resolvedHost = address.family === "IPv4" ? address.address : `[${address.address}]`;
|
|
42
|
+
if (resolvedHost === "0.0.0.0" || resolvedHost === "[::]") {
|
|
43
|
+
resolvedHost = "localhost";
|
|
44
|
+
}
|
|
45
|
+
return `http://${resolvedHost}:${resolvedPort}`;
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
startHttpServer,
|
|
49
|
+
httpAddressToString
|
|
50
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/in-process-client.ts
|
|
21
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
22
|
+
import { ListRootsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
23
|
+
import { BrowserServerBackend } from "./browser-server-backend.js";
|
|
24
|
+
import { InProcessTransport } from "./mcp/in-process-transport.js";
|
|
25
|
+
import { createServer } from "./mcp/server.js";
|
|
26
|
+
import { packageJSON } from "./package.js";
|
|
27
|
+
|
|
28
|
+
class InProcessClientFactory {
|
|
29
|
+
name;
|
|
30
|
+
description;
|
|
31
|
+
_contextFactory;
|
|
32
|
+
_config;
|
|
33
|
+
constructor(contextFactory, config) {
|
|
34
|
+
this.name = contextFactory.name;
|
|
35
|
+
this.description = contextFactory.description;
|
|
36
|
+
this._contextFactory = contextFactory;
|
|
37
|
+
this._config = config;
|
|
38
|
+
}
|
|
39
|
+
async create(server) {
|
|
40
|
+
const client = new Client(server.getClientVersion() ?? {
|
|
41
|
+
name: this.name,
|
|
42
|
+
version: packageJSON.version
|
|
43
|
+
});
|
|
44
|
+
const clientCapabilities = server.getClientCapabilities();
|
|
45
|
+
if (clientCapabilities) {
|
|
46
|
+
client.registerCapabilities(clientCapabilities);
|
|
47
|
+
}
|
|
48
|
+
if (clientCapabilities?.roots) {
|
|
49
|
+
client.setRequestHandler(ListRootsRequestSchema, async () => {
|
|
50
|
+
return await server.listRoots();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const backend = new BrowserServerBackend(this._config, [
|
|
54
|
+
this._contextFactory
|
|
55
|
+
]);
|
|
56
|
+
const delegate = createServer(backend, false);
|
|
57
|
+
await client.connect(new InProcessTransport(delegate));
|
|
58
|
+
await client.ping();
|
|
59
|
+
return client;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
InProcessClientFactory
|
|
64
|
+
};
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
import { contextFactory } from "./browser-context-factory.js";
|
|
22
|
+
import { BrowserServerBackend } from "./browser-server-backend.js";
|
|
23
|
+
import { resolveConfig } from "./config.js";
|
|
24
|
+
import { createServer } from "./mcp/server.js";
|
|
25
|
+
function createConnection(userConfig = {}, contextGetter) {
|
|
26
|
+
const config = resolveConfig(userConfig);
|
|
27
|
+
const factory = contextGetter ? new SimpleBrowserContextFactory(contextGetter) : contextFactory(config);
|
|
28
|
+
return createServer(new BrowserServerBackend(config, [factory]), false);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class SimpleBrowserContextFactory {
|
|
32
|
+
name = "custom";
|
|
33
|
+
description = "Connect to a browser using a custom context getter";
|
|
34
|
+
_contextGetter;
|
|
35
|
+
constructor(contextGetter) {
|
|
36
|
+
this._contextGetter = contextGetter;
|
|
37
|
+
}
|
|
38
|
+
async createContext() {
|
|
39
|
+
const browserContext = await this._contextGetter();
|
|
40
|
+
return {
|
|
41
|
+
browserContext,
|
|
42
|
+
close: () => browserContext.close()
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
createConnection
|
|
48
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/javascript.ts
|
|
21
|
+
function escapeWithQuotes(text, char = "'") {
|
|
22
|
+
const stringified = JSON.stringify(text);
|
|
23
|
+
const escapedText = extractEscapedContent(stringified);
|
|
24
|
+
return wrapWithCharacter(escapedText, char);
|
|
25
|
+
}
|
|
26
|
+
function extractEscapedContent(stringified) {
|
|
27
|
+
return stringified.substring(1, stringified.length - 1).replace(/\\"/g, '"');
|
|
28
|
+
}
|
|
29
|
+
function wrapWithCharacter(text, char) {
|
|
30
|
+
const replacements = {
|
|
31
|
+
"'": "'",
|
|
32
|
+
'"': '"',
|
|
33
|
+
"`": "`"
|
|
34
|
+
};
|
|
35
|
+
const replacement = replacements[char];
|
|
36
|
+
if (!replacement) {
|
|
37
|
+
throw new Error("Invalid escape char");
|
|
38
|
+
}
|
|
39
|
+
let result = text;
|
|
40
|
+
if (char === "'") {
|
|
41
|
+
result = text.replaceAll("'", "'");
|
|
42
|
+
} else if (char === '"') {
|
|
43
|
+
result = text.replaceAll('"', '"');
|
|
44
|
+
} else if (char === "`") {
|
|
45
|
+
result = text.replaceAll("`", "`");
|
|
46
|
+
}
|
|
47
|
+
return char + result + char;
|
|
48
|
+
}
|
|
49
|
+
function quote(text) {
|
|
50
|
+
return escapeWithQuotes(text, "'");
|
|
51
|
+
}
|
|
52
|
+
function formatObject(value, indent = " ") {
|
|
53
|
+
if (typeof value === "string") {
|
|
54
|
+
return quote(value);
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
return formatArray(value);
|
|
58
|
+
}
|
|
59
|
+
if (typeof value === "object" && value !== null) {
|
|
60
|
+
return formatObjectValue(value, indent);
|
|
61
|
+
}
|
|
62
|
+
return String(value);
|
|
63
|
+
}
|
|
64
|
+
function formatArray(arr) {
|
|
65
|
+
return `[${arr.map((o) => formatObject(o)).join(", ")}]`;
|
|
66
|
+
}
|
|
67
|
+
function formatObjectValue(obj, indent) {
|
|
68
|
+
const keys = getValidObjectKeys(obj);
|
|
69
|
+
if (keys.length === 0) {
|
|
70
|
+
return "{}";
|
|
71
|
+
}
|
|
72
|
+
return buildObjectString(obj, keys, indent);
|
|
73
|
+
}
|
|
74
|
+
function getValidObjectKeys(obj) {
|
|
75
|
+
return Object.keys(obj).filter((key) => obj[key] !== undefined).sort((a, b) => a.localeCompare(b, "en", { numeric: true }));
|
|
76
|
+
}
|
|
77
|
+
function buildObjectString(obj, keys, indent) {
|
|
78
|
+
const tokens = keys.map((key) => `${key}: ${formatObject(obj[key])}`);
|
|
79
|
+
const separator = `,
|
|
80
|
+
${indent}`;
|
|
81
|
+
const tokensJoined = tokens.join(separator);
|
|
82
|
+
return `{
|
|
83
|
+
${indent}${tokensJoined}
|
|
84
|
+
}`;
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
quote,
|
|
88
|
+
formatObject,
|
|
89
|
+
escapeWithQuotes
|
|
90
|
+
};
|
package/lib/log.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/log.ts
|
|
21
|
+
import debug from "debug";
|
|
22
|
+
var errorsDebug = debug("pw:mcp:errors");
|
|
23
|
+
var requestsDebug = debug("pw:mcp:requests");
|
|
24
|
+
function logUnhandledError(error) {
|
|
25
|
+
errorsDebug(error);
|
|
26
|
+
}
|
|
27
|
+
var testDebug = debug("pw:mcp:test");
|
|
28
|
+
var requestDebug = requestsDebug;
|
|
29
|
+
export {
|
|
30
|
+
testDebug,
|
|
31
|
+
requestDebug,
|
|
32
|
+
logUnhandledError
|
|
33
|
+
};
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
+
for (let key of __getOwnPropNames(mod))
|
|
11
|
+
if (!__hasOwnProp.call(to, key))
|
|
12
|
+
__defProp(to, key, {
|
|
13
|
+
get: () => mod[key],
|
|
14
|
+
enumerable: true
|
|
15
|
+
});
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
|
+
|
|
20
|
+
// src/loop/loop-claude.ts
|
|
21
|
+
var model = "claude-sonnet-4-20250514";
|
|
22
|
+
|
|
23
|
+
class ClaudeDelegate {
|
|
24
|
+
_anthropic;
|
|
25
|
+
async anthropic() {
|
|
26
|
+
if (!this._anthropic) {
|
|
27
|
+
const anthropic = await import("@anthropic-ai/sdk");
|
|
28
|
+
this._anthropic = new anthropic.Anthropic;
|
|
29
|
+
}
|
|
30
|
+
return this._anthropic;
|
|
31
|
+
}
|
|
32
|
+
createConversation(task, tools, oneShot) {
|
|
33
|
+
const llmTools = tools.map((tool) => ({
|
|
34
|
+
name: tool.name,
|
|
35
|
+
description: tool.description ?? "",
|
|
36
|
+
inputSchema: tool.inputSchema
|
|
37
|
+
}));
|
|
38
|
+
if (!oneShot) {
|
|
39
|
+
llmTools.push({
|
|
40
|
+
name: "done",
|
|
41
|
+
description: "Call this tool when the task is complete.",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
messages: [
|
|
50
|
+
{
|
|
51
|
+
role: "user",
|
|
52
|
+
content: task
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
tools: llmTools
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
async makeApiCall(conversation) {
|
|
59
|
+
const formattedData = this.formatConversationData(conversation);
|
|
60
|
+
const response = await this.callClaudeApi(formattedData.claudeMessages, formattedData.claudeTools);
|
|
61
|
+
return this.processApiResponse(conversation, response);
|
|
62
|
+
}
|
|
63
|
+
processApiResponse(conversation, response) {
|
|
64
|
+
return this.processResponseAndUpdateConversation(conversation, response);
|
|
65
|
+
}
|
|
66
|
+
processResponseAndUpdateConversation(conversation, response) {
|
|
67
|
+
const llmToolCalls = this.extractToolCallsFromResponse(response);
|
|
68
|
+
this.addAssistantMessageToConversation(conversation, response, llmToolCalls);
|
|
69
|
+
return llmToolCalls;
|
|
70
|
+
}
|
|
71
|
+
formatConversationData(conversation) {
|
|
72
|
+
return {
|
|
73
|
+
claudeMessages: this.convertMessagesToClaudeFormat(conversation.messages),
|
|
74
|
+
claudeTools: this.convertToolsToClaudeFormat(conversation.tools)
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
convertMessagesToClaudeFormat(messages) {
|
|
78
|
+
return this.buildClaudeMessagesFromConversation(messages);
|
|
79
|
+
}
|
|
80
|
+
buildClaudeMessagesFromConversation(messages) {
|
|
81
|
+
const claudeMessages = [];
|
|
82
|
+
for (const message of messages) {
|
|
83
|
+
this.processMessageByType(claudeMessages, message);
|
|
84
|
+
}
|
|
85
|
+
return claudeMessages;
|
|
86
|
+
}
|
|
87
|
+
processMessageByType(claudeMessages, message) {
|
|
88
|
+
this.delegateMessageProcessing(claudeMessages, message);
|
|
89
|
+
}
|
|
90
|
+
delegateMessageProcessing(claudeMessages, message) {
|
|
91
|
+
switch (message.role) {
|
|
92
|
+
case "user":
|
|
93
|
+
this.addUserMessage(claudeMessages, message);
|
|
94
|
+
break;
|
|
95
|
+
case "assistant":
|
|
96
|
+
this.addAssistantMessage(claudeMessages, message);
|
|
97
|
+
break;
|
|
98
|
+
case "tool":
|
|
99
|
+
this.addToolResultMessage(claudeMessages, message);
|
|
100
|
+
break;
|
|
101
|
+
default:
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
addUserMessage(claudeMessages, message) {
|
|
106
|
+
if (message.role === "user") {
|
|
107
|
+
claudeMessages.push({
|
|
108
|
+
role: "user",
|
|
109
|
+
content: message.content
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
addAssistantMessage(claudeMessages, message) {
|
|
114
|
+
if (message.role !== "assistant") {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const content = this.buildAssistantContent(message);
|
|
118
|
+
claudeMessages.push({
|
|
119
|
+
role: "assistant",
|
|
120
|
+
content
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
buildAssistantContent(message) {
|
|
124
|
+
const content = [];
|
|
125
|
+
this.populateContentBlocks(content, message);
|
|
126
|
+
return content;
|
|
127
|
+
}
|
|
128
|
+
populateContentBlocks(content, message) {
|
|
129
|
+
this.addTextContentIfPresent(content, message.content);
|
|
130
|
+
this.addToolCallsIfPresent(content, message);
|
|
131
|
+
}
|
|
132
|
+
addTextContentIfPresent(content, textContent) {
|
|
133
|
+
if (!textContent) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
content.push({
|
|
137
|
+
type: "text",
|
|
138
|
+
text: textContent,
|
|
139
|
+
citations: []
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
addToolCallsIfPresent(content, message) {
|
|
143
|
+
if (message.role !== "assistant" || !message.toolCalls) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
this.addToolCallsToContent(content, message.toolCalls);
|
|
147
|
+
}
|
|
148
|
+
addToolCallsToContent(content, toolCalls) {
|
|
149
|
+
for (const toolCall of toolCalls) {
|
|
150
|
+
content.push({
|
|
151
|
+
type: "tool_use",
|
|
152
|
+
id: toolCall.id,
|
|
153
|
+
name: toolCall.name,
|
|
154
|
+
input: toolCall.arguments
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
addToolResultMessage(claudeMessages, message) {
|
|
159
|
+
if (message.role !== "tool") {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const toolResult = this.createToolResultBlock(message);
|
|
163
|
+
this.appendToolResultToMessages(claudeMessages, toolResult);
|
|
164
|
+
}
|
|
165
|
+
createToolResultBlock(message) {
|
|
166
|
+
return {
|
|
167
|
+
type: "tool_result",
|
|
168
|
+
tool_use_id: message.toolCallId,
|
|
169
|
+
content: message.content,
|
|
170
|
+
is_error: message.isError
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
appendToolResultToMessages(claudeMessages, toolResult) {
|
|
174
|
+
const lastMessage = claudeMessages.at(-1);
|
|
175
|
+
this.handleToolResultAppending(claudeMessages, lastMessage, toolResult);
|
|
176
|
+
}
|
|
177
|
+
handleToolResultAppending(claudeMessages, lastMessage, toolResult) {
|
|
178
|
+
if (this.canAddToExistingToolResults(lastMessage)) {
|
|
179
|
+
this.addToExistingMessage(lastMessage, toolResult);
|
|
180
|
+
} else {
|
|
181
|
+
this.createNewToolResultMessage(claudeMessages, toolResult);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
addToExistingMessage(lastMessage, toolResult) {
|
|
185
|
+
lastMessage.content.push(toolResult);
|
|
186
|
+
}
|
|
187
|
+
createNewToolResultMessage(claudeMessages, toolResult) {
|
|
188
|
+
claudeMessages.push({
|
|
189
|
+
role: "user",
|
|
190
|
+
content: [toolResult]
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
canAddToExistingToolResults(lastMessage) {
|
|
194
|
+
return !!(lastMessage && lastMessage.role === "user" && Array.isArray(lastMessage.content));
|
|
195
|
+
}
|
|
196
|
+
convertToolsToClaudeFormat(tools) {
|
|
197
|
+
return tools.map((tool) => ({
|
|
198
|
+
name: tool.name,
|
|
199
|
+
description: tool.description,
|
|
200
|
+
input_schema: tool.inputSchema
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
async callClaudeApi(claudeMessages, claudeTools) {
|
|
204
|
+
const anthropic = await this.anthropic();
|
|
205
|
+
return await anthropic.messages.create({
|
|
206
|
+
model,
|
|
207
|
+
max_tokens: 1e4,
|
|
208
|
+
messages: claudeMessages,
|
|
209
|
+
tools: claudeTools
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
extractToolCallsFromResponse(response) {
|
|
213
|
+
const toolCalls = response.content.filter((block) => block.type === "tool_use");
|
|
214
|
+
return toolCalls.map((toolCall) => ({
|
|
215
|
+
name: toolCall.name,
|
|
216
|
+
arguments: toolCall.input,
|
|
217
|
+
id: toolCall.id
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
addAssistantMessageToConversation(conversation, response, llmToolCalls) {
|
|
221
|
+
const textContent = response.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
222
|
+
conversation.messages.push({
|
|
223
|
+
role: "assistant",
|
|
224
|
+
content: textContent,
|
|
225
|
+
toolCalls: llmToolCalls.length > 0 ? llmToolCalls : undefined
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
addToolResults(conversation, results) {
|
|
229
|
+
for (const result of results) {
|
|
230
|
+
conversation.messages.push({
|
|
231
|
+
role: "tool",
|
|
232
|
+
toolCallId: result.toolCallId,
|
|
233
|
+
content: result.content,
|
|
234
|
+
isError: result.isError
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
checkDoneToolCall(toolCall) {
|
|
239
|
+
if (toolCall.name === "done") {
|
|
240
|
+
return toolCall.arguments.result;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export {
|
|
246
|
+
ClaudeDelegate
|
|
247
|
+
};
|