@mearl/native-host 2.2.1 → 2.3.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/dist/agent/codex-provider.d.ts +9 -0
- package/dist/agent/executable-resolver.d.ts +12 -0
- package/dist/agent/process-env.d.ts +2 -6
- package/dist/agent/qoder-provider.d.ts +10 -0
- package/dist/agent/skill-manager.d.ts +4 -8
- package/dist/cdp-backend/buffers.d.ts +9 -4
- package/dist/cdp-backend/cdp-session.d.ts +1 -0
- package/dist/cdp-backend/composite-handlers.d.ts +4 -5
- package/dist/cdp-backend/request-handlers.d.ts +3 -1
- package/dist/index.js +909 -420
- package/dist/install.d.ts +18 -0
- package/dist/install.js +110 -40
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -9,40 +9,102 @@ var __export = (target, all) => {
|
|
|
9
9
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
+
// ../setup/dist/nativeHost.js
|
|
13
|
+
import fs9 from "node:fs";
|
|
14
|
+
import os6 from "node:os";
|
|
15
|
+
import path10 from "node:path";
|
|
16
|
+
import { execFileSync } from "node:child_process";
|
|
17
|
+
function resolveNativeHostDirectory(options = {}) {
|
|
18
|
+
const env = options.env ?? process.env;
|
|
19
|
+
const home = (options.homedir ?? os6.homedir)();
|
|
20
|
+
switch (options.platform ?? process.platform) {
|
|
21
|
+
case "darwin":
|
|
22
|
+
return path10.join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts");
|
|
23
|
+
case "linux":
|
|
24
|
+
return path10.join(home, ".config/google-chrome/NativeMessagingHosts");
|
|
25
|
+
case "win32":
|
|
26
|
+
return path10.join(env.PROGRAMDATA || "C:\\ProgramData", "Google\\Chrome\\NativeMessagingHosts");
|
|
27
|
+
default:
|
|
28
|
+
throw new Error(`Unsupported platform: ${String(options.platform ?? process.platform)}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function unregisterWindowsNativeHost(hostName) {
|
|
32
|
+
const registryKey = `HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`;
|
|
33
|
+
try {
|
|
34
|
+
execFileSync("reg", ["delete", registryKey, "/f"], { stdio: "pipe" });
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function uninstallNativeHostArtifacts(options = {}, dependencies = {}) {
|
|
39
|
+
const { mode = "both", silent = false } = options;
|
|
40
|
+
if (mode === "both") {
|
|
41
|
+
return ["skills", "mcp"].map((integrationMode) => uninstallNativeHostArtifacts({ ...options, mode: integrationMode }, dependencies)).every(Boolean);
|
|
42
|
+
}
|
|
43
|
+
const writeLine = dependencies.writeLine ?? ((line) => console.error(line));
|
|
44
|
+
const log2 = (line) => {
|
|
45
|
+
if (!silent)
|
|
46
|
+
writeLine(line);
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
const existsSync4 = dependencies.existsSync ?? fs9.existsSync;
|
|
50
|
+
const platform = dependencies.platform ?? process.platform;
|
|
51
|
+
const hostDir = dependencies.hostDir ?? resolveNativeHostDirectory({
|
|
52
|
+
env: dependencies.env,
|
|
53
|
+
homedir: dependencies.homedir,
|
|
54
|
+
platform
|
|
55
|
+
});
|
|
56
|
+
const unlinkSync = dependencies.unlinkSync ?? fs9.unlinkSync;
|
|
57
|
+
const unregister = dependencies.unregisterWindowsNativeHost ?? unregisterWindowsNativeHost;
|
|
58
|
+
const hostName = MEARL_NATIVE_HOST_NAMES[mode];
|
|
59
|
+
const launcherExtension = platform === "win32" ? "cmd" : "sh";
|
|
60
|
+
const artifacts = [
|
|
61
|
+
path10.join(hostDir, `${hostName}.json`),
|
|
62
|
+
path10.join(hostDir, `${hostName}-launcher.${launcherExtension}`)
|
|
63
|
+
];
|
|
64
|
+
for (const artifact of artifacts) {
|
|
65
|
+
if (!existsSync4(artifact))
|
|
66
|
+
continue;
|
|
67
|
+
unlinkSync(artifact);
|
|
68
|
+
log2(`✅ Removed: ${artifact}`);
|
|
69
|
+
}
|
|
70
|
+
if (platform === "win32")
|
|
71
|
+
unregister(hostName);
|
|
72
|
+
return true;
|
|
73
|
+
} catch (error48) {
|
|
74
|
+
log2(`❌ Uninstall failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
var MEARL_NATIVE_HOST_NAMES;
|
|
79
|
+
var init_nativeHost = __esm({
|
|
80
|
+
"../setup/dist/nativeHost.js"() {
|
|
81
|
+
"use strict";
|
|
82
|
+
MEARL_NATIVE_HOST_NAMES = {
|
|
83
|
+
skills: "com.alibaba.mearl.skills",
|
|
84
|
+
mcp: "com.alibaba.mearl.mcp"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
12
89
|
// src/install.ts
|
|
13
90
|
var install_exports = {};
|
|
14
91
|
__export(install_exports, {
|
|
15
92
|
installNativeHost: () => installNativeHost,
|
|
16
93
|
resolveHostDir: () => resolveHostDir,
|
|
17
|
-
runCli: () => runCli
|
|
94
|
+
runCli: () => runCli,
|
|
95
|
+
uninstallNativeHost: () => uninstallNativeHost
|
|
18
96
|
});
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
import { execFileSync } from "node:child_process";
|
|
97
|
+
import fs10 from "node:fs";
|
|
98
|
+
import path11 from "node:path";
|
|
99
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
23
100
|
import { createRequire } from "node:module";
|
|
24
101
|
import { fileURLToPath } from "node:url";
|
|
25
102
|
function resolveHostDir() {
|
|
26
|
-
|
|
27
|
-
case "darwin":
|
|
28
|
-
return path10.join(
|
|
29
|
-
os6.homedir(),
|
|
30
|
-
"Library/Application Support/Google/Chrome/NativeMessagingHosts"
|
|
31
|
-
);
|
|
32
|
-
case "linux":
|
|
33
|
-
return path10.join(os6.homedir(), ".config/google-chrome/NativeMessagingHosts");
|
|
34
|
-
case "win32":
|
|
35
|
-
return path10.join(
|
|
36
|
-
process.env.PROGRAMDATA || "C:\\ProgramData",
|
|
37
|
-
"Google\\Chrome\\NativeMessagingHosts"
|
|
38
|
-
);
|
|
39
|
-
default:
|
|
40
|
-
throw new Error(`Unsupported platform: ${process.platform}`);
|
|
41
|
-
}
|
|
103
|
+
return resolveNativeHostDirectory();
|
|
42
104
|
}
|
|
43
105
|
function resolveNativeHostPath() {
|
|
44
|
-
const siblingPath =
|
|
45
|
-
if (
|
|
106
|
+
const siblingPath = path11.join(__dirname, "index.js");
|
|
107
|
+
if (fs10.existsSync(siblingPath)) {
|
|
46
108
|
return siblingPath;
|
|
47
109
|
}
|
|
48
110
|
try {
|
|
@@ -56,21 +118,21 @@ function resolveNativeHostPath() {
|
|
|
56
118
|
}
|
|
57
119
|
function registerWindowsNativeHost(hostName, manifestPath) {
|
|
58
120
|
const regKey = `HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\${hostName}`;
|
|
59
|
-
|
|
121
|
+
execFileSync2("reg", ["add", regKey, "/ve", "/t", "REG_SZ", "/d", manifestPath, "/f"], {
|
|
60
122
|
stdio: "pipe"
|
|
61
123
|
});
|
|
62
124
|
}
|
|
63
125
|
function createLauncherScript(hostDir, hostPath, hostName) {
|
|
64
|
-
const nodePath =
|
|
126
|
+
const nodePath = path11.resolve(process.execPath);
|
|
65
127
|
if (process.platform === "win32") {
|
|
66
|
-
const launcherPath2 =
|
|
128
|
+
const launcherPath2 = path11.join(hostDir, `${hostName}-launcher.cmd`);
|
|
67
129
|
const content2 = `@echo off\r
|
|
68
130
|
"${nodePath}" "${hostPath}" %*\r
|
|
69
131
|
`;
|
|
70
|
-
|
|
132
|
+
fs10.writeFileSync(launcherPath2, content2, "utf-8");
|
|
71
133
|
return launcherPath2;
|
|
72
134
|
}
|
|
73
|
-
const launcherPath =
|
|
135
|
+
const launcherPath = path11.join(hostDir, `${hostName}-launcher.sh`);
|
|
74
136
|
const content = [
|
|
75
137
|
"#!/bin/sh",
|
|
76
138
|
`NODE_BIN=${JSON.stringify(nodePath)}`,
|
|
@@ -78,8 +140,8 @@ function createLauncherScript(hostDir, hostPath, hostName) {
|
|
|
78
140
|
'exec "$NODE_BIN" "$HOST_SCRIPT" "$@"',
|
|
79
141
|
""
|
|
80
142
|
].join("\n");
|
|
81
|
-
|
|
82
|
-
|
|
143
|
+
fs10.writeFileSync(launcherPath, content, "utf-8");
|
|
144
|
+
fs10.chmodSync(launcherPath, 493);
|
|
83
145
|
return launcherPath;
|
|
84
146
|
}
|
|
85
147
|
async function installNativeHost(options = {}) {
|
|
@@ -95,7 +157,7 @@ async function installNativeHost(options = {}) {
|
|
|
95
157
|
);
|
|
96
158
|
return results.every(Boolean);
|
|
97
159
|
}
|
|
98
|
-
const hostName =
|
|
160
|
+
const hostName = MEARL_NATIVE_HOST_NAMES[mode];
|
|
99
161
|
if (!hostName) {
|
|
100
162
|
throw new Error(`Unknown mode: ${mode}. Expected 'skills' or 'mcp'.`);
|
|
101
163
|
}
|
|
@@ -105,14 +167,14 @@ async function installNativeHost(options = {}) {
|
|
|
105
167
|
try {
|
|
106
168
|
const hostDir = resolveHostDir();
|
|
107
169
|
if (skipIfExists) {
|
|
108
|
-
const manifestPath2 =
|
|
109
|
-
if (
|
|
170
|
+
const manifestPath2 = path11.join(hostDir, `${hostName}.json`);
|
|
171
|
+
if (fs10.existsSync(manifestPath2)) {
|
|
110
172
|
log2(`✅ Already installed: ${manifestPath2}`);
|
|
111
173
|
return true;
|
|
112
174
|
}
|
|
113
175
|
}
|
|
114
|
-
if (!
|
|
115
|
-
|
|
176
|
+
if (!fs10.existsSync(hostDir)) {
|
|
177
|
+
fs10.mkdirSync(hostDir, { recursive: true });
|
|
116
178
|
log2(`✅ Created directory: ${hostDir}`);
|
|
117
179
|
}
|
|
118
180
|
const resolvedHostPath = resolveNativeHostPath();
|
|
@@ -126,13 +188,13 @@ async function installNativeHost(options = {}) {
|
|
|
126
188
|
type: "stdio",
|
|
127
189
|
allowed_origins: [`chrome-extension://${extensionId}/`]
|
|
128
190
|
};
|
|
129
|
-
const manifestPath =
|
|
130
|
-
|
|
191
|
+
const manifestPath = path11.join(hostDir, `${hostName}.json`);
|
|
192
|
+
fs10.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
131
193
|
if (process.platform === "win32") {
|
|
132
194
|
registerWindowsNativeHost(hostName, manifestPath);
|
|
133
195
|
log2(`✅ Windows registry key created for: ${hostName}`);
|
|
134
196
|
} else {
|
|
135
|
-
|
|
197
|
+
fs10.chmodSync(manifestPath, 420);
|
|
136
198
|
}
|
|
137
199
|
log2(`✅ Manifest installed: ${manifestPath}`);
|
|
138
200
|
log2(`✅ Extension ID: ${extensionId}`);
|
|
@@ -146,14 +208,18 @@ async function installNativeHost(options = {}) {
|
|
|
146
208
|
return false;
|
|
147
209
|
}
|
|
148
210
|
}
|
|
211
|
+
async function uninstallNativeHost(options = {}, dependencies = {}) {
|
|
212
|
+
return uninstallNativeHostArtifacts(options, dependencies);
|
|
213
|
+
}
|
|
149
214
|
function parseCliArgs(argv) {
|
|
150
215
|
let mode = "both";
|
|
151
216
|
let extensionId;
|
|
152
217
|
let skipIfExists = false;
|
|
218
|
+
let uninstall = false;
|
|
153
219
|
for (let i = 0; i < argv.length; i += 1) {
|
|
154
220
|
const arg = argv[i];
|
|
155
221
|
if (arg === "--help" || arg === "-h") {
|
|
156
|
-
return { showHelp: true, mode, skipIfExists };
|
|
222
|
+
return { showHelp: true, uninstall, mode, skipIfExists };
|
|
157
223
|
}
|
|
158
224
|
if (arg === "--mode" || arg.startsWith("--mode=")) {
|
|
159
225
|
const value = arg.includes("=") ? arg.slice("--mode=".length) : argv[++i];
|
|
@@ -172,24 +238,31 @@ function parseCliArgs(argv) {
|
|
|
172
238
|
skipIfExists = true;
|
|
173
239
|
continue;
|
|
174
240
|
}
|
|
241
|
+
if (arg === "--uninstall") {
|
|
242
|
+
uninstall = true;
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
175
245
|
if (arg === "--init") {
|
|
176
246
|
continue;
|
|
177
247
|
}
|
|
178
248
|
}
|
|
179
|
-
return { showHelp: false, mode, extensionId, skipIfExists };
|
|
249
|
+
return { showHelp: false, uninstall, mode, extensionId, skipIfExists };
|
|
180
250
|
}
|
|
181
251
|
function printHelp() {
|
|
182
252
|
console.error(`Usage:
|
|
183
253
|
mearl-native-host --init [options]
|
|
254
|
+
mearl-native-host --uninstall [options]
|
|
184
255
|
|
|
185
256
|
Options:
|
|
186
257
|
--mode <skills|mcp|both> Integration mode (default: both — installs both hosts)
|
|
187
258
|
--extension-id <id> Chrome extension ID (default: ${DEFAULT_EXTENSION_ID})
|
|
259
|
+
--uninstall Remove the selected Native Messaging manifests
|
|
188
260
|
-h, --help Show this help message
|
|
189
261
|
|
|
190
262
|
Examples:
|
|
191
263
|
mearl-native-host --init
|
|
192
264
|
mearl-native-host --init --mode mcp
|
|
265
|
+
mearl-native-host --uninstall --mode skills
|
|
193
266
|
mearl-native-host --init --extension-id abcdefghijklmnopqrstuvwxyzabcdef`);
|
|
194
267
|
}
|
|
195
268
|
async function runCli(argv) {
|
|
@@ -203,6 +276,11 @@ async function runCli(argv) {
|
|
|
203
276
|
console.error(" Must be a 32-character lowercase string (see chrome://extensions/)");
|
|
204
277
|
process.exit(1);
|
|
205
278
|
}
|
|
279
|
+
if (parsed.uninstall) {
|
|
280
|
+
const success3 = await uninstallNativeHost({ mode: parsed.mode });
|
|
281
|
+
if (success3) console.error("\n✅ Uninstall complete!\n");
|
|
282
|
+
process.exit(success3 ? 0 : 1);
|
|
283
|
+
}
|
|
206
284
|
const success2 = await installNativeHost({
|
|
207
285
|
mode: parsed.mode,
|
|
208
286
|
extensionId: parsed.extensionId,
|
|
@@ -222,27 +300,24 @@ Verify:
|
|
|
222
300
|
}
|
|
223
301
|
process.exit(success2 ? 0 : 1);
|
|
224
302
|
}
|
|
225
|
-
var DEFAULT_EXTENSION_ID,
|
|
303
|
+
var DEFAULT_EXTENSION_ID, __filename, __dirname, ALL_MODES;
|
|
226
304
|
var init_install = __esm({
|
|
227
305
|
"src/install.ts"() {
|
|
228
306
|
"use strict";
|
|
307
|
+
init_nativeHost();
|
|
229
308
|
DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm";
|
|
230
|
-
HOST_NAME_BY_MODE = {
|
|
231
|
-
skills: "com.alibaba.mearl.skills",
|
|
232
|
-
mcp: "com.alibaba.mearl.mcp"
|
|
233
|
-
};
|
|
234
309
|
__filename = fileURLToPath(import.meta.url);
|
|
235
|
-
__dirname =
|
|
310
|
+
__dirname = path11.dirname(__filename);
|
|
236
311
|
ALL_MODES = ["skills", "mcp"];
|
|
237
312
|
}
|
|
238
313
|
});
|
|
239
314
|
|
|
240
315
|
// src/index.ts
|
|
241
316
|
import net from "node:net";
|
|
242
|
-
import
|
|
317
|
+
import fs11 from "node:fs";
|
|
243
318
|
import http5 from "node:http";
|
|
244
319
|
import os7 from "node:os";
|
|
245
|
-
import
|
|
320
|
+
import path12 from "node:path";
|
|
246
321
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
247
322
|
|
|
248
323
|
// src/cdp-backend/cdp-session.ts
|
|
@@ -250,7 +325,7 @@ import http3 from "node:http";
|
|
|
250
325
|
|
|
251
326
|
// src/cdp-backend/client.ts
|
|
252
327
|
import http from "node:http";
|
|
253
|
-
import
|
|
328
|
+
import crypto2 from "node:crypto";
|
|
254
329
|
var CdpChildSession = class {
|
|
255
330
|
constructor(parent, sessionId) {
|
|
256
331
|
this.parent = parent;
|
|
@@ -331,8 +406,8 @@ var CdpClient = class _CdpClient {
|
|
|
331
406
|
return new Promise((resolve, reject) => {
|
|
332
407
|
const url2 = new URL(wsUrl);
|
|
333
408
|
const port = parseInt(url2.port || "9222", 10);
|
|
334
|
-
const key =
|
|
335
|
-
const expectedAccept =
|
|
409
|
+
const key = crypto2.randomBytes(16).toString("base64");
|
|
410
|
+
const expectedAccept = crypto2.createHash("sha1").update(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").digest("base64");
|
|
336
411
|
const req = http.request({
|
|
337
412
|
host: url2.hostname,
|
|
338
413
|
port,
|
|
@@ -484,7 +559,7 @@ var CdpClient = class _CdpClient {
|
|
|
484
559
|
sendText(text) {
|
|
485
560
|
if (this._closed) return;
|
|
486
561
|
const payload = Buffer.from(text, "utf-8");
|
|
487
|
-
const maskKey =
|
|
562
|
+
const maskKey = crypto2.randomBytes(4);
|
|
488
563
|
const masked = Buffer.from(payload.map((b, i) => b ^ maskKey[i % 4]));
|
|
489
564
|
let header;
|
|
490
565
|
if (payload.length < 126) {
|
|
@@ -679,6 +754,9 @@ function buildCookieHeaderValue(cookieMap) {
|
|
|
679
754
|
var APLUS_URL_PATTERN = /\.mmstat\.com\//;
|
|
680
755
|
var RUM_URL_PATTERN = /\.rum\.aliyuncs\.com\//;
|
|
681
756
|
var ARMS_URL_PATTERN = /arms-retcode\.aliyuncs\.com\//;
|
|
757
|
+
function isTrackingUrl(url2) {
|
|
758
|
+
return APLUS_URL_PATTERN.test(url2) || RUM_URL_PATTERN.test(url2) || ARMS_URL_PATTERN.test(url2) || /retcode\.alicdn\.com|beacon\.taobao\.com|tbsec\./i.test(url2);
|
|
759
|
+
}
|
|
682
760
|
var aplusCounter = 0;
|
|
683
761
|
var armsCounter = 0;
|
|
684
762
|
var rumCounter = 0;
|
|
@@ -1088,13 +1166,13 @@ function queryTrackingEvents(buffer, options = {}) {
|
|
|
1088
1166
|
}
|
|
1089
1167
|
|
|
1090
1168
|
// ../browser-core/dist/requestSerializer.js
|
|
1091
|
-
function parsePath(
|
|
1092
|
-
if (
|
|
1169
|
+
function parsePath(path13) {
|
|
1170
|
+
if (path13.length > 1e3)
|
|
1093
1171
|
throw new Error("Path too long: maximum 1000 characters allowed");
|
|
1094
1172
|
const keys = [];
|
|
1095
1173
|
let current = "";
|
|
1096
|
-
for (let i = 0; i <
|
|
1097
|
-
const char =
|
|
1174
|
+
for (let i = 0; i < path13.length; i++) {
|
|
1175
|
+
const char = path13[i];
|
|
1098
1176
|
if (char === ".") {
|
|
1099
1177
|
if (current) {
|
|
1100
1178
|
keys.push(current);
|
|
@@ -1106,10 +1184,10 @@ function parsePath(path12) {
|
|
|
1106
1184
|
current = "";
|
|
1107
1185
|
}
|
|
1108
1186
|
let j = i + 1;
|
|
1109
|
-
while (j <
|
|
1187
|
+
while (j < path13.length && path13[j] !== "]")
|
|
1110
1188
|
j++;
|
|
1111
|
-
if (j <
|
|
1112
|
-
const index = parseInt(
|
|
1189
|
+
if (j < path13.length) {
|
|
1190
|
+
const index = parseInt(path13.substring(i + 1, j), 10);
|
|
1113
1191
|
if (!isNaN(index)) {
|
|
1114
1192
|
if (index < 0 || index > 1e5)
|
|
1115
1193
|
throw new Error(`Array index out of safe range: ${index}`);
|
|
@@ -1127,8 +1205,8 @@ function parsePath(path12) {
|
|
|
1127
1205
|
throw new Error("Path too deep: maximum 50 levels allowed");
|
|
1128
1206
|
return keys;
|
|
1129
1207
|
}
|
|
1130
|
-
function getValueByPath(obj,
|
|
1131
|
-
const keys = parsePath(
|
|
1208
|
+
function getValueByPath(obj, path13) {
|
|
1209
|
+
const keys = parsePath(path13);
|
|
1132
1210
|
let current = obj;
|
|
1133
1211
|
for (const key of keys) {
|
|
1134
1212
|
if (current === null || current === void 0)
|
|
@@ -1137,8 +1215,8 @@ function getValueByPath(obj, path12) {
|
|
|
1137
1215
|
}
|
|
1138
1216
|
return current;
|
|
1139
1217
|
}
|
|
1140
|
-
function setValueByPath(obj,
|
|
1141
|
-
const keys = parsePath(
|
|
1218
|
+
function setValueByPath(obj, path13, value) {
|
|
1219
|
+
const keys = parsePath(path13);
|
|
1142
1220
|
let current = obj;
|
|
1143
1221
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
1144
1222
|
const key = keys[i];
|
|
@@ -1212,7 +1290,11 @@ function serializeRequest(request, options = {}) {
|
|
|
1212
1290
|
status: request.status,
|
|
1213
1291
|
statusText: request.statusText,
|
|
1214
1292
|
queryString: request.queryString,
|
|
1215
|
-
duration: request.duration
|
|
1293
|
+
duration: request.duration,
|
|
1294
|
+
captureSequence: request.captureSequence,
|
|
1295
|
+
isPending: request.isPending,
|
|
1296
|
+
source: request.source,
|
|
1297
|
+
resourceType: request.resourceType
|
|
1216
1298
|
};
|
|
1217
1299
|
if (includeHeaders) {
|
|
1218
1300
|
result.headers = request.headers;
|
|
@@ -1336,10 +1418,14 @@ function applyFieldLimits(request, maxFieldBytes) {
|
|
|
1336
1418
|
request.responseBody = limitBufferedField(request.responseBody, maxFieldBytes);
|
|
1337
1419
|
}
|
|
1338
1420
|
function trimRequestBuffer(requests, accounting, maxEntries, maxBytes) {
|
|
1421
|
+
const removed = [];
|
|
1339
1422
|
while (requests.length > 1 && (requests.length > maxEntries || accounting.totalBytes > maxBytes)) {
|
|
1340
|
-
requests.shift();
|
|
1423
|
+
const request = requests.shift();
|
|
1424
|
+
if (request)
|
|
1425
|
+
removed.push(request);
|
|
1341
1426
|
accounting.totalBytes -= accounting.sizes.shift() ?? 0;
|
|
1342
1427
|
}
|
|
1428
|
+
return removed;
|
|
1343
1429
|
}
|
|
1344
1430
|
function appendRequestToBuffer(requests, accounting, request, limits = {}) {
|
|
1345
1431
|
const { maxEntries = REQUEST_BUFFER_MAX_ENTRIES, maxBytes = REQUEST_BUFFER_MAX_BYTES, maxFieldBytes = REQUEST_BUFFER_MAX_FIELD_BYTES } = limits;
|
|
@@ -1349,20 +1435,20 @@ function appendRequestToBuffer(requests, accounting, request, limits = {}) {
|
|
|
1349
1435
|
requests.push(request);
|
|
1350
1436
|
accounting.sizes.push(size);
|
|
1351
1437
|
accounting.totalBytes += size;
|
|
1352
|
-
trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1438
|
+
return trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1353
1439
|
}
|
|
1354
1440
|
function refreshRequestInBuffer(requests, accounting, request, limits = {}) {
|
|
1355
1441
|
const { maxEntries = REQUEST_BUFFER_MAX_ENTRIES, maxBytes = REQUEST_BUFFER_MAX_BYTES, maxFieldBytes = REQUEST_BUFFER_MAX_FIELD_BYTES } = limits;
|
|
1356
1442
|
const index = requests.indexOf(request);
|
|
1357
1443
|
if (index === -1)
|
|
1358
|
-
return;
|
|
1444
|
+
return [];
|
|
1359
1445
|
synchronizeAccounting(requests, accounting);
|
|
1360
1446
|
applyFieldLimits(request, maxFieldBytes);
|
|
1361
1447
|
const previousSize = accounting.sizes[index] ?? 0;
|
|
1362
1448
|
const nextSize = estimateRequestBufferBytes(request);
|
|
1363
1449
|
accounting.sizes[index] = nextSize;
|
|
1364
1450
|
accounting.totalBytes += nextSize - previousSize;
|
|
1365
|
-
trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1451
|
+
return trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1366
1452
|
}
|
|
1367
1453
|
|
|
1368
1454
|
// ../browser-core/dist/proxyPermissions.js
|
|
@@ -2141,6 +2227,24 @@ var CHECKABLE_AX_ROLES = /* @__PURE__ */ new Set([
|
|
|
2141
2227
|
"radio",
|
|
2142
2228
|
"switch"
|
|
2143
2229
|
]);
|
|
2230
|
+
function resolveDOMSnapshotViewportBounds(metrics) {
|
|
2231
|
+
const viewport = metrics.visualViewport ?? metrics.cssVisualViewport;
|
|
2232
|
+
return normalizePageViewportBounds({
|
|
2233
|
+
left: viewport?.pageX ?? 0,
|
|
2234
|
+
top: viewport?.pageY ?? 0,
|
|
2235
|
+
width: viewport?.clientWidth,
|
|
2236
|
+
height: viewport?.clientHeight
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
function normalizePageViewportBounds(value) {
|
|
2240
|
+
if (!value || typeof value !== "object")
|
|
2241
|
+
return null;
|
|
2242
|
+
const { left, top, width, height } = value;
|
|
2243
|
+
if (typeof left !== "number" || typeof top !== "number" || typeof width !== "number" || typeof height !== "number" || !Number.isFinite(left) || !Number.isFinite(top) || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
|
|
2244
|
+
return null;
|
|
2245
|
+
}
|
|
2246
|
+
return { left, top, width, height };
|
|
2247
|
+
}
|
|
2144
2248
|
function readDOMCheckedState() {
|
|
2145
2249
|
const tag = String(this && this.tagName || "").toLowerCase();
|
|
2146
2250
|
const type = String(this && this.type || "").toLowerCase();
|
|
@@ -2648,19 +2752,19 @@ function installPageObserverInPage(maxBatches = 50) {
|
|
|
2648
2752
|
}
|
|
2649
2753
|
}
|
|
2650
2754
|
}
|
|
2651
|
-
const
|
|
2755
|
+
const path13 = [];
|
|
2652
2756
|
let current = input;
|
|
2653
|
-
while (current && current !== document.documentElement &&
|
|
2757
|
+
while (current && current !== document.documentElement && path13.length < 6) {
|
|
2654
2758
|
const parent = current.parentElement;
|
|
2655
2759
|
const currentTag = current.tagName.toLowerCase();
|
|
2656
2760
|
if (!parent) {
|
|
2657
|
-
|
|
2761
|
+
path13.unshift(currentTag);
|
|
2658
2762
|
break;
|
|
2659
2763
|
}
|
|
2660
2764
|
const siblings = Array.from(parent.children).filter((item) => item.tagName === current.tagName);
|
|
2661
2765
|
const position = siblings.indexOf(current) + 1;
|
|
2662
|
-
|
|
2663
|
-
const candidate =
|
|
2766
|
+
path13.unshift(siblings.length > 1 ? `${currentTag}:nth-of-type(${position})` : currentTag);
|
|
2767
|
+
const candidate = path13.join(" > ");
|
|
2664
2768
|
if (input.isConnected) {
|
|
2665
2769
|
try {
|
|
2666
2770
|
if (document.querySelectorAll(candidate).length === 1)
|
|
@@ -2670,7 +2774,7 @@ function installPageObserverInPage(maxBatches = 50) {
|
|
|
2670
2774
|
}
|
|
2671
2775
|
current = parent;
|
|
2672
2776
|
}
|
|
2673
|
-
return
|
|
2777
|
+
return path13.join(" > ") || void 0;
|
|
2674
2778
|
};
|
|
2675
2779
|
const inferredRole = (element) => {
|
|
2676
2780
|
const explicit = element.getAttribute("role");
|
|
@@ -3377,6 +3481,7 @@ var PAGE_ACT_ACTIONS = [
|
|
|
3377
3481
|
"page_eval"
|
|
3378
3482
|
];
|
|
3379
3483
|
var BROWSER_COMMAND_ACTIONS = {
|
|
3484
|
+
capture_checkpoint: true,
|
|
3380
3485
|
get_requests: true,
|
|
3381
3486
|
get_logs: true,
|
|
3382
3487
|
get_events: true,
|
|
@@ -3419,6 +3524,7 @@ var BROWSER_COMMAND_ACTIONS = {
|
|
|
3419
3524
|
run_actions: true
|
|
3420
3525
|
};
|
|
3421
3526
|
var EXTENSION_BROWSER_ACTIONS = {
|
|
3527
|
+
capture_checkpoint: true,
|
|
3422
3528
|
get_requests: true,
|
|
3423
3529
|
get_logs: true,
|
|
3424
3530
|
get_events: true,
|
|
@@ -3465,24 +3571,35 @@ function isExtensionBrowserAction(value) {
|
|
|
3465
3571
|
}
|
|
3466
3572
|
|
|
3467
3573
|
// ../browser-core/dist/pageAct.js
|
|
3574
|
+
var DEFAULT_PAGE_DIAGNOSTICS = {
|
|
3575
|
+
logs: true,
|
|
3576
|
+
requests: true
|
|
3577
|
+
};
|
|
3468
3578
|
function isPageActAction(action) {
|
|
3469
3579
|
return PAGE_ACT_ACTIONS.includes(action);
|
|
3470
3580
|
}
|
|
3471
3581
|
function shouldObservePageAction(action, data) {
|
|
3472
3582
|
if (!isPageActAction(action))
|
|
3473
3583
|
return false;
|
|
3584
|
+
const diagnosticsEnabled = data?.diagnostics !== void 0 && data.diagnostics !== false;
|
|
3474
3585
|
if (action === "page_eval") {
|
|
3475
|
-
return Boolean(data?.observe && typeof data.observe === "object" && !Array.isArray(data.observe));
|
|
3586
|
+
return Boolean(diagnosticsEnabled || data?.observe && typeof data.observe === "object" && !Array.isArray(data.observe));
|
|
3476
3587
|
}
|
|
3477
|
-
return data?.observe !== false;
|
|
3588
|
+
return data?.observe !== false || data?.diagnostics !== false;
|
|
3478
3589
|
}
|
|
3479
|
-
function splitObservedActionPayload(data) {
|
|
3480
|
-
const { observe, ...actionData } = data ?? {};
|
|
3590
|
+
function splitObservedActionPayload(action, data) {
|
|
3591
|
+
const { observe, diagnostics, ...actionData } = data ?? {};
|
|
3592
|
+
const setting = diagnostics;
|
|
3593
|
+
const resolvedDiagnostics = setting === false ? void 0 : setting === true ? DEFAULT_PAGE_DIAGNOSTICS : setting && typeof setting === "object" && !Array.isArray(setting) ? setting : action === "page_eval" ? void 0 : DEFAULT_PAGE_DIAGNOSTICS;
|
|
3481
3594
|
if (observe === false)
|
|
3482
|
-
return { actionData, observe: false };
|
|
3595
|
+
return { actionData, observe: false, diagnostics: resolvedDiagnostics };
|
|
3596
|
+
if (action === "page_eval" && (!observe || typeof observe !== "object")) {
|
|
3597
|
+
return { actionData, observe: false, diagnostics: resolvedDiagnostics };
|
|
3598
|
+
}
|
|
3483
3599
|
return {
|
|
3484
3600
|
actionData,
|
|
3485
|
-
observe: observe && typeof observe === "object" && !Array.isArray(observe) ? observe : {}
|
|
3601
|
+
observe: observe && typeof observe === "object" && !Array.isArray(observe) ? observe : {},
|
|
3602
|
+
diagnostics: resolvedDiagnostics
|
|
3486
3603
|
};
|
|
3487
3604
|
}
|
|
3488
3605
|
function unavailableObservation(checkpoint, error48) {
|
|
@@ -4176,6 +4293,20 @@ function assertSendRequestBase64FileLimits(byteLengths) {
|
|
|
4176
4293
|
}
|
|
4177
4294
|
}
|
|
4178
4295
|
|
|
4296
|
+
// ../browser-core/dist/sendRequestHeaders.js
|
|
4297
|
+
function resolveHeader(headers, name, fallback) {
|
|
4298
|
+
const key = findSendRequestHeaderName(headers, name);
|
|
4299
|
+
if (!key)
|
|
4300
|
+
return fallback;
|
|
4301
|
+
return headers[key] === "" ? void 0 : headers[key];
|
|
4302
|
+
}
|
|
4303
|
+
function getSendRequestSourceHeaders(targetUrl, headers = {}) {
|
|
4304
|
+
return {
|
|
4305
|
+
referer: resolveHeader(headers, "Referer", `${targetUrl.origin}/mearl`),
|
|
4306
|
+
origin: resolveHeader(headers, "Origin", targetUrl.origin)
|
|
4307
|
+
};
|
|
4308
|
+
}
|
|
4309
|
+
|
|
4179
4310
|
// ../browser-core/dist/cookie.js
|
|
4180
4311
|
function normalizeCookieDomain(input, action) {
|
|
4181
4312
|
const value = input.trim();
|
|
@@ -4278,12 +4409,12 @@ function resolveGetCookieTarget(currentUrl, input) {
|
|
|
4278
4409
|
const url2 = parseCurrentUrl(currentUrl, action);
|
|
4279
4410
|
const name = validateCookieName(input?.name, action);
|
|
4280
4411
|
const domain2 = resolveExplicitDomain(url2, input?.domain, action);
|
|
4281
|
-
const
|
|
4412
|
+
const path13 = validateCookiePath(input?.path, action);
|
|
4282
4413
|
return {
|
|
4283
4414
|
cookieName: name,
|
|
4284
|
-
cookieUrl: `${url2.protocol}//${url2.hostname}${(
|
|
4415
|
+
cookieUrl: `${url2.protocol}//${url2.hostname}${(path13 ?? url2.pathname) || "/"}`,
|
|
4285
4416
|
...domain2 ? { domain: domain2 } : {},
|
|
4286
|
-
...
|
|
4417
|
+
...path13 ? { path: path13 } : {}
|
|
4287
4418
|
};
|
|
4288
4419
|
}
|
|
4289
4420
|
function resolveSetCookieTarget(currentUrl, input) {
|
|
@@ -4291,7 +4422,7 @@ function resolveSetCookieTarget(currentUrl, input) {
|
|
|
4291
4422
|
const url2 = parseCurrentUrl(currentUrl, action);
|
|
4292
4423
|
const name = validateCookieName(input?.name, action);
|
|
4293
4424
|
const value = validateCookieValue(input?.value);
|
|
4294
|
-
const
|
|
4425
|
+
const path13 = validateCookiePath(input?.path, action) ?? "/";
|
|
4295
4426
|
if (input.reload !== void 0 && typeof input.reload !== "boolean") {
|
|
4296
4427
|
throw new Error('set_cookie: "reload" must be a boolean');
|
|
4297
4428
|
}
|
|
@@ -4301,9 +4432,9 @@ function resolveSetCookieTarget(currentUrl, input) {
|
|
|
4301
4432
|
cookieName: name,
|
|
4302
4433
|
cookieValue: value,
|
|
4303
4434
|
...explicitDomain ? { cookieDomain: explicitDomain.includes(".") ? `.${explicitDomain}` : explicitDomain } : {},
|
|
4304
|
-
cookieUrl: `${url2.protocol}//${url2.hostname.toLowerCase()}${
|
|
4435
|
+
cookieUrl: `${url2.protocol}//${url2.hostname.toLowerCase()}${path13}`,
|
|
4305
4436
|
domain: domain2,
|
|
4306
|
-
path:
|
|
4437
|
+
path: path13,
|
|
4307
4438
|
reload: input.reload === true
|
|
4308
4439
|
};
|
|
4309
4440
|
}
|
|
@@ -4319,10 +4450,7 @@ var SOURCE_BADGES = {
|
|
|
4319
4450
|
<circle cx="104" cy="104" r="21" fill="#16A34A" stroke="#FFFFFF" stroke-width="6"/>
|
|
4320
4451
|
`,
|
|
4321
4452
|
cloud: `
|
|
4322
|
-
<
|
|
4323
|
-
C111 85 106 82 100 82C91 82 85 89 84 97C78 99 75 104 75 109
|
|
4324
|
-
C75 116 81 121 89 121H91Z" fill="#7C3AED" stroke="#FFFFFF" stroke-width="6"
|
|
4325
|
-
stroke-linejoin="round"/>
|
|
4453
|
+
<circle cx="104" cy="104" r="21" fill="#FF7A00" stroke="#FFFFFF" stroke-width="6"/>
|
|
4326
4454
|
`
|
|
4327
4455
|
};
|
|
4328
4456
|
function createControlledFaviconDataUrl(source) {
|
|
@@ -4333,6 +4461,83 @@ ${SOURCE_BADGES[source]}
|
|
|
4333
4461
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
4334
4462
|
}
|
|
4335
4463
|
|
|
4464
|
+
// ../browser-core/dist/capture.js
|
|
4465
|
+
var CURSOR_PREFIX = "mearl-capture-v1";
|
|
4466
|
+
function createCaptureGeneration() {
|
|
4467
|
+
return crypto.randomUUID();
|
|
4468
|
+
}
|
|
4469
|
+
function encodeCaptureCursor(cursor) {
|
|
4470
|
+
return `${CURSOR_PREFIX}:${cursor.tabId}:${cursor.generation}:${cursor.scope}:${cursor.sequence}`;
|
|
4471
|
+
}
|
|
4472
|
+
function decodeCaptureCursor(value) {
|
|
4473
|
+
const match = value.match(/^mearl-capture-v1:(\d+):([^:]+):(all|logs|requests):(\d+)$/);
|
|
4474
|
+
if (!match)
|
|
4475
|
+
throw new Error("Invalid capture cursor");
|
|
4476
|
+
const tabId = Number(match[1]);
|
|
4477
|
+
const sequence = Number(match[4]);
|
|
4478
|
+
if (!Number.isSafeInteger(tabId) || !Number.isSafeInteger(sequence)) {
|
|
4479
|
+
throw new Error("Invalid capture cursor");
|
|
4480
|
+
}
|
|
4481
|
+
return {
|
|
4482
|
+
tabId,
|
|
4483
|
+
generation: match[2],
|
|
4484
|
+
scope: match[3],
|
|
4485
|
+
sequence
|
|
4486
|
+
};
|
|
4487
|
+
}
|
|
4488
|
+
function captureCheckpoint(state) {
|
|
4489
|
+
return encodeCaptureCursor({
|
|
4490
|
+
tabId: state.tabId,
|
|
4491
|
+
generation: state.generation,
|
|
4492
|
+
sequence: state.currentSequence,
|
|
4493
|
+
scope: "all"
|
|
4494
|
+
});
|
|
4495
|
+
}
|
|
4496
|
+
function nextCaptureSequence(state) {
|
|
4497
|
+
state.currentSequence += 1;
|
|
4498
|
+
return state.currentSequence;
|
|
4499
|
+
}
|
|
4500
|
+
function resolveAfterSequence(after, state, scope) {
|
|
4501
|
+
if (!after)
|
|
4502
|
+
return 0;
|
|
4503
|
+
const cursor = decodeCaptureCursor(after);
|
|
4504
|
+
if (cursor.tabId !== state.tabId) {
|
|
4505
|
+
throw new Error(`Capture cursor belongs to tab ${cursor.tabId}, not tab ${state.tabId}`);
|
|
4506
|
+
}
|
|
4507
|
+
if (cursor.generation !== state.generation) {
|
|
4508
|
+
throw new Error("Capture cursor expired because the tab collector was restarted");
|
|
4509
|
+
}
|
|
4510
|
+
if (cursor.scope !== "all" && cursor.scope !== scope) {
|
|
4511
|
+
throw new Error(`Capture cursor is scoped to ${cursor.scope}, not ${scope}`);
|
|
4512
|
+
}
|
|
4513
|
+
if (cursor.sequence > state.currentSequence) {
|
|
4514
|
+
throw new Error("Capture cursor is ahead of the current collector state");
|
|
4515
|
+
}
|
|
4516
|
+
return cursor.sequence;
|
|
4517
|
+
}
|
|
4518
|
+
function queryCapturedEntries(buffer, state, options, matches, droppedThroughSequence = 0, scope = "all") {
|
|
4519
|
+
const { after, since, now = Date.now() } = options;
|
|
4520
|
+
const limit = Math.max(1, Math.floor(options.limit ?? 100));
|
|
4521
|
+
const afterSequence = resolveAfterSequence(after, state, scope);
|
|
4522
|
+
const sinceTimestampMs = since === void 0 ? void 0 : now - since * 1e3;
|
|
4523
|
+
const matched = buffer.filter((entry) => entry.captureSequence > afterSequence && (sinceTimestampMs === void 0 || entry.timestampMs >= sinceTimestampMs) && matches(entry));
|
|
4524
|
+
const hasMore = matched.length > limit;
|
|
4525
|
+
const entries = after ? matched.slice(0, limit) : matched.slice(-limit);
|
|
4526
|
+
const nextSequence = after && hasMore && entries.length > 0 ? entries[entries.length - 1].captureSequence : state.currentSequence;
|
|
4527
|
+
return {
|
|
4528
|
+
entries,
|
|
4529
|
+
totalMatched: matched.length,
|
|
4530
|
+
nextCursor: encodeCaptureCursor({
|
|
4531
|
+
tabId: state.tabId,
|
|
4532
|
+
generation: state.generation,
|
|
4533
|
+
sequence: nextSequence,
|
|
4534
|
+
scope
|
|
4535
|
+
}),
|
|
4536
|
+
hasMore,
|
|
4537
|
+
gap: after !== void 0 && afterSequence < droppedThroughSequence
|
|
4538
|
+
};
|
|
4539
|
+
}
|
|
4540
|
+
|
|
4336
4541
|
// src/cdp-backend/domain-manager.ts
|
|
4337
4542
|
var enabledDomains = /* @__PURE__ */ new WeakMap();
|
|
4338
4543
|
function ensureCdpDomain(client2, domain2, params = {}) {
|
|
@@ -4354,14 +4559,22 @@ function ensureCdpDomain(client2, domain2, params = {}) {
|
|
|
4354
4559
|
// src/cdp-backend/buffers.ts
|
|
4355
4560
|
var MAX_LOGS = 500;
|
|
4356
4561
|
var MAX_EVENTS = 500;
|
|
4357
|
-
|
|
4562
|
+
var COLLECTED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["xhr", "fetch", "document"]);
|
|
4563
|
+
function createBuffers(tabId = 0) {
|
|
4358
4564
|
return {
|
|
4359
4565
|
requests: [],
|
|
4360
4566
|
logs: [],
|
|
4361
4567
|
events: [],
|
|
4362
4568
|
pending: /* @__PURE__ */ new Map(),
|
|
4363
4569
|
requestCounter: 0,
|
|
4364
|
-
requestBufferAccounting: createRequestBufferAccounting()
|
|
4570
|
+
requestBufferAccounting: createRequestBufferAccounting(),
|
|
4571
|
+
capture: {
|
|
4572
|
+
tabId,
|
|
4573
|
+
generation: createCaptureGeneration(),
|
|
4574
|
+
currentSequence: 0,
|
|
4575
|
+
droppedRequestsThroughSequence: 0,
|
|
4576
|
+
droppedLogsThroughSequence: 0
|
|
4577
|
+
}
|
|
4365
4578
|
};
|
|
4366
4579
|
}
|
|
4367
4580
|
function parseQueryString(url2) {
|
|
@@ -4377,12 +4590,34 @@ function parseQueryString(url2) {
|
|
|
4377
4590
|
function headersObjToArray(obj) {
|
|
4378
4591
|
return Object.entries(obj).map(([name, value]) => ({ name, value }));
|
|
4379
4592
|
}
|
|
4380
|
-
function
|
|
4593
|
+
function extractMtopApiName(url2, postData) {
|
|
4381
4594
|
try {
|
|
4382
4595
|
const u = new URL(url2);
|
|
4383
|
-
const
|
|
4384
|
-
if (
|
|
4385
|
-
|
|
4596
|
+
const pathMatch = u.pathname.match(/\/h5\/([\w.]+)\//);
|
|
4597
|
+
if (pathMatch) return pathMatch[1];
|
|
4598
|
+
const requestUrl = u.searchParams.get("requestUrl");
|
|
4599
|
+
const proxyMatch = requestUrl?.match(/\b(?:mtop|mopen)\.[\w.]+/);
|
|
4600
|
+
if (proxyMatch) return proxyMatch[0];
|
|
4601
|
+
} catch {
|
|
4602
|
+
}
|
|
4603
|
+
const urlMatch = url2.match(/\b(?:mtop|mopen)\.[\w.]+/);
|
|
4604
|
+
if (urlMatch) return urlMatch[0];
|
|
4605
|
+
if (!postData) return null;
|
|
4606
|
+
try {
|
|
4607
|
+
const parsed = JSON.parse(postData);
|
|
4608
|
+
const requestUrl = typeof parsed?.requestUrl === "string" ? parsed.requestUrl : void 0;
|
|
4609
|
+
const proxyMatch = requestUrl?.match(/\b(?:mtop|mopen)\.[\w.]+/);
|
|
4610
|
+
if (proxyMatch) return proxyMatch[0];
|
|
4611
|
+
} catch {
|
|
4612
|
+
const requestUrl = new URLSearchParams(postData).get("requestUrl");
|
|
4613
|
+
const proxyMatch = requestUrl?.match(/\b(?:mtop|mopen)\.[\w.]+/);
|
|
4614
|
+
if (proxyMatch) return proxyMatch[0];
|
|
4615
|
+
}
|
|
4616
|
+
return null;
|
|
4617
|
+
}
|
|
4618
|
+
function requestDisplayName(url2) {
|
|
4619
|
+
try {
|
|
4620
|
+
return new URL(url2).pathname;
|
|
4386
4621
|
} catch {
|
|
4387
4622
|
return url2;
|
|
4388
4623
|
}
|
|
@@ -4413,28 +4648,73 @@ function appendTrackingEvents(buffers, url2, postData, sequence) {
|
|
|
4413
4648
|
}
|
|
4414
4649
|
return true;
|
|
4415
4650
|
}
|
|
4416
|
-
function
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4651
|
+
function recordDroppedRequests(buffers, removed) {
|
|
4652
|
+
for (const request of removed) {
|
|
4653
|
+
if (request.captureSequence !== void 0) {
|
|
4654
|
+
buffers.capture.droppedRequestsThroughSequence = Math.max(
|
|
4655
|
+
buffers.capture.droppedRequestsThroughSequence,
|
|
4656
|
+
request.captureSequence
|
|
4657
|
+
);
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
}
|
|
4661
|
+
function appendCapturedRequest(buffers, request) {
|
|
4662
|
+
recordDroppedRequests(
|
|
4663
|
+
buffers,
|
|
4664
|
+
appendRequestToBuffer(buffers.requests, buffers.requestBufferAccounting, request)
|
|
4665
|
+
);
|
|
4666
|
+
}
|
|
4667
|
+
function refreshCapturedRequest(buffers, request) {
|
|
4668
|
+
recordDroppedRequests(
|
|
4669
|
+
buffers,
|
|
4670
|
+
refreshRequestInBuffer(buffers.requests, buffers.requestBufferAccounting, request)
|
|
4671
|
+
);
|
|
4672
|
+
}
|
|
4673
|
+
function appendCapturedLog(buffers, log2) {
|
|
4674
|
+
buffers.logs.push({ ...log2, captureSequence: nextCaptureSequence(buffers.capture) });
|
|
4675
|
+
if (buffers.logs.length > MAX_LOGS) {
|
|
4676
|
+
const removed = buffers.logs.shift();
|
|
4677
|
+
if (removed) buffers.capture.droppedLogsThroughSequence = removed.captureSequence;
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
async function setupBufferListeners(client2, buffers) {
|
|
4426
4681
|
client2.on("Network.requestWillBeSent", (params) => {
|
|
4427
4682
|
const url2 = params.request?.url ?? "";
|
|
4428
|
-
|
|
4683
|
+
if (!url2.startsWith("http")) return;
|
|
4684
|
+
if (isTrackingUrl(url2)) {
|
|
4685
|
+
const sequence = ++buffers.requestCounter;
|
|
4686
|
+
const captured = appendTrackingEvents(buffers, url2, params.request?.postData, sequence);
|
|
4687
|
+
if (!captured && params.request?.hasPostData && !params.request?.postData) {
|
|
4688
|
+
client2.sendCommand("Network.getRequestPostData", { requestId: params.requestId }, 1e4).then((result) => appendTrackingEvents(buffers, url2, result?.postData, sequence)).catch(() => {
|
|
4689
|
+
});
|
|
4690
|
+
}
|
|
4691
|
+
return;
|
|
4692
|
+
}
|
|
4693
|
+
const resourceType = String(params.type ?? "").toLowerCase();
|
|
4694
|
+
const mtopApiName = extractMtopApiName(url2, params.request?.postData);
|
|
4695
|
+
const isMtop = mtopApiName !== null;
|
|
4696
|
+
if (!isMtop && !COLLECTED_RESOURCE_TYPES.has(resourceType)) return;
|
|
4697
|
+
const ts = params.timestamp;
|
|
4698
|
+
const timestampMs2 = params.wallTime !== void 0 ? Math.floor(params.wallTime * 1e3) : Date.now();
|
|
4699
|
+
const redirected = buffers.pending.get(params.requestId);
|
|
4700
|
+
if (redirected && params.redirectResponse) {
|
|
4701
|
+
redirected.status = params.redirectResponse.status ?? 0;
|
|
4702
|
+
redirected.statusText = params.redirectResponse.statusText ?? "";
|
|
4703
|
+
redirected.duration = ts !== void 0 && redirected.startTs !== void 0 ? Math.round((ts - redirected.startTs) * 1e3) : void 0;
|
|
4704
|
+
redirected.isPending = false;
|
|
4705
|
+
refreshCapturedRequest(buffers, redirected);
|
|
4706
|
+
buffers.pending.delete(params.requestId);
|
|
4707
|
+
}
|
|
4429
4708
|
const id = ++buffers.requestCounter;
|
|
4709
|
+
const captureSequence = nextCaptureSequence(buffers.capture);
|
|
4430
4710
|
const partial2 = {
|
|
4431
4711
|
id,
|
|
4432
4712
|
requestId: params.requestId,
|
|
4433
|
-
timestamp: new Date(
|
|
4434
|
-
timestampMs:
|
|
4713
|
+
timestamp: new Date(timestampMs2).toISOString(),
|
|
4714
|
+
timestampMs: timestampMs2,
|
|
4435
4715
|
method: params.request?.method ?? "GET",
|
|
4436
4716
|
url: url2,
|
|
4437
|
-
apiName:
|
|
4717
|
+
apiName: mtopApiName ?? requestDisplayName(url2),
|
|
4438
4718
|
headers: headersObjToArray(params.request?.headers ?? {}),
|
|
4439
4719
|
postData: parsePostData(params.request?.postData),
|
|
4440
4720
|
queryString: parseQueryString(url2),
|
|
@@ -4445,16 +4725,14 @@ function setupBufferListeners(client2, buffers) {
|
|
|
4445
4725
|
isProxy: false,
|
|
4446
4726
|
proxyRequestUrl: null,
|
|
4447
4727
|
proxyData: null,
|
|
4448
|
-
startTs: ts
|
|
4728
|
+
startTs: ts,
|
|
4729
|
+
captureSequence,
|
|
4730
|
+
isPending: true,
|
|
4731
|
+
source: isMtop ? "mtop" : "requests",
|
|
4732
|
+
resourceType
|
|
4449
4733
|
};
|
|
4450
4734
|
buffers.pending.set(params.requestId, partial2);
|
|
4451
|
-
|
|
4452
|
-
if (!captured && params.request?.hasPostData && !params.request?.postData) {
|
|
4453
|
-
client2.sendCommand("Network.getRequestPostData", { requestId: params.requestId }, 1e4).then((result) => {
|
|
4454
|
-
appendTrackingEvents(buffers, url2, result?.postData, id);
|
|
4455
|
-
}).catch(() => {
|
|
4456
|
-
});
|
|
4457
|
-
}
|
|
4735
|
+
appendCapturedRequest(buffers, partial2);
|
|
4458
4736
|
});
|
|
4459
4737
|
client2.on("Network.responseReceived", (params) => {
|
|
4460
4738
|
const partial2 = buffers.pending.get(params.requestId);
|
|
@@ -4462,73 +4740,110 @@ function setupBufferListeners(client2, buffers) {
|
|
|
4462
4740
|
partial2.status = params.response?.status ?? 0;
|
|
4463
4741
|
partial2.statusText = params.response?.statusText ?? "";
|
|
4464
4742
|
partial2.responseHeaders = headersObjToArray(params.response?.headers ?? {});
|
|
4743
|
+
refreshCapturedRequest(buffers, partial2);
|
|
4465
4744
|
});
|
|
4466
4745
|
client2.on("Network.loadingFinished", (params) => {
|
|
4467
4746
|
const partial2 = buffers.pending.get(params.requestId);
|
|
4468
4747
|
if (!partial2) return;
|
|
4469
4748
|
buffers.pending.delete(params.requestId);
|
|
4470
|
-
const endTs = params.timestamp
|
|
4471
|
-
const duration3 = Math.round((endTs - partial2.startTs) * 1e3);
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
isPending: false
|
|
4476
|
-
};
|
|
4749
|
+
const endTs = params.timestamp;
|
|
4750
|
+
const duration3 = endTs !== void 0 && partial2.startTs !== void 0 ? Math.round((endTs - partial2.startTs) * 1e3) : void 0;
|
|
4751
|
+
partial2.duration = duration3;
|
|
4752
|
+
partial2.isPending = false;
|
|
4753
|
+
refreshCapturedRequest(buffers, partial2);
|
|
4477
4754
|
client2.sendCommand("Network.getResponseBody", { requestId: params.requestId }, 1e4).then((result) => {
|
|
4478
|
-
|
|
4479
|
-
if (typeof
|
|
4755
|
+
partial2.responseBody = result.base64Encoded ? Buffer.from(result.body, "base64").toString("utf-8") : result.body;
|
|
4756
|
+
if (typeof partial2.responseBody === "string") {
|
|
4480
4757
|
try {
|
|
4481
|
-
|
|
4758
|
+
partial2.responseBody = JSON.parse(partial2.responseBody);
|
|
4482
4759
|
} catch {
|
|
4483
4760
|
}
|
|
4484
4761
|
}
|
|
4485
|
-
|
|
4762
|
+
refreshCapturedRequest(buffers, partial2);
|
|
4486
4763
|
}).catch(() => {
|
|
4487
4764
|
});
|
|
4488
|
-
appendRequestToBuffer(buffers.requests, buffers.requestBufferAccounting, req);
|
|
4489
4765
|
});
|
|
4490
4766
|
client2.on("Network.loadingFailed", (params) => {
|
|
4491
4767
|
const partial2 = buffers.pending.get(params.requestId);
|
|
4492
4768
|
if (!partial2) return;
|
|
4493
4769
|
buffers.pending.delete(params.requestId);
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
isPending: false
|
|
4500
|
-
};
|
|
4501
|
-
appendRequestToBuffer(buffers.requests, buffers.requestBufferAccounting, req);
|
|
4770
|
+
partial2.status = 0;
|
|
4771
|
+
partial2.statusText = params.errorText ?? "Failed";
|
|
4772
|
+
partial2.duration = params.timestamp !== void 0 && partial2.startTs !== void 0 ? Math.round((params.timestamp - partial2.startTs) * 1e3) : void 0;
|
|
4773
|
+
partial2.isPending = false;
|
|
4774
|
+
refreshCapturedRequest(buffers, partial2);
|
|
4502
4775
|
});
|
|
4503
4776
|
client2.on("Runtime.consoleAPICalled", (params) => {
|
|
4504
|
-
const
|
|
4777
|
+
const levelMap = {
|
|
4778
|
+
warning: "warn",
|
|
4779
|
+
debug: "debug",
|
|
4780
|
+
info: "info",
|
|
4781
|
+
error: "error",
|
|
4782
|
+
assert: "error"
|
|
4783
|
+
};
|
|
4784
|
+
const level = levelMap[params.type] ?? "log";
|
|
4505
4785
|
const args = (params.args ?? []).map((arg) => {
|
|
4506
4786
|
if (arg.type === "string") return arg.value;
|
|
4507
4787
|
if (arg.value !== void 0) return String(arg.value);
|
|
4508
4788
|
if (arg.description !== void 0) return arg.description;
|
|
4509
4789
|
return JSON.stringify(arg);
|
|
4510
4790
|
});
|
|
4511
|
-
|
|
4791
|
+
appendCapturedLog(buffers, {
|
|
4512
4792
|
level,
|
|
4513
4793
|
message: args.join(" "),
|
|
4514
|
-
|
|
4515
|
-
source: "console",
|
|
4516
|
-
args
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4794
|
+
timestampMs: params.timestamp ?? Date.now(),
|
|
4795
|
+
source: params.stackTrace?.callFrames?.[0]?.url ? `${params.stackTrace.callFrames[0].url.split("/").pop() || params.stackTrace.callFrames[0].url}:${params.stackTrace.callFrames[0].lineNumber + 1}` : "console",
|
|
4796
|
+
args,
|
|
4797
|
+
origin: "console"
|
|
4798
|
+
});
|
|
4799
|
+
});
|
|
4800
|
+
client2.on("Runtime.exceptionThrown", (params) => {
|
|
4801
|
+
const details = params.exceptionDetails ?? {};
|
|
4802
|
+
const exception = details.exception;
|
|
4803
|
+
const message = exception?.description ?? (exception?.value !== void 0 ? String(exception.value) : void 0) ?? details.text ?? "Uncaught exception";
|
|
4804
|
+
const topFrame = details.stackTrace?.callFrames?.[0];
|
|
4805
|
+
const url2 = topFrame?.url || details.url;
|
|
4806
|
+
const lineNumber = topFrame?.lineNumber ?? details.lineNumber;
|
|
4807
|
+
const source = url2 ? `${url2.split("/").pop() || url2}${lineNumber !== void 0 ? `:${lineNumber + 1}` : ""}` : void 0;
|
|
4808
|
+
appendCapturedLog(buffers, {
|
|
4809
|
+
level: "error",
|
|
4810
|
+
message,
|
|
4811
|
+
timestampMs: params.timestamp ?? Date.now(),
|
|
4812
|
+
...source ? { source } : {},
|
|
4813
|
+
args: [message],
|
|
4814
|
+
origin: "exception"
|
|
4815
|
+
});
|
|
4520
4816
|
});
|
|
4521
4817
|
client2.on("Log.entryAdded", (params) => {
|
|
4522
|
-
const entry = {
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
|
|
4527
|
-
|
|
4818
|
+
const entry = params.entry ?? {};
|
|
4819
|
+
const levelMap = {
|
|
4820
|
+
verbose: "log",
|
|
4821
|
+
info: "info",
|
|
4822
|
+
warning: "warn",
|
|
4823
|
+
error: "error"
|
|
4528
4824
|
};
|
|
4529
|
-
|
|
4530
|
-
|
|
4825
|
+
const args = (entry.args ?? []).map((arg) => {
|
|
4826
|
+
if (arg.value !== void 0) return String(arg.value);
|
|
4827
|
+
return arg.description ?? `[${arg.type || "Object"}]`;
|
|
4828
|
+
});
|
|
4829
|
+
const message = entry.text || args.join(" ");
|
|
4830
|
+
appendCapturedLog(buffers, {
|
|
4831
|
+
level: levelMap[entry.level] ?? entry.level ?? "log",
|
|
4832
|
+
message,
|
|
4833
|
+
timestampMs: entry.timestamp ?? Date.now(),
|
|
4834
|
+
source: entry.url ? `${entry.url.split("/").pop() || entry.url}${entry.lineNumber !== void 0 ? `:${entry.lineNumber + 1}` : ""}` : entry.source ?? "other",
|
|
4835
|
+
args: args.length > 0 ? args : [message],
|
|
4836
|
+
origin: "browser"
|
|
4837
|
+
});
|
|
4531
4838
|
});
|
|
4839
|
+
await Promise.all([
|
|
4840
|
+
ensureCdpDomain(client2, "Network", {
|
|
4841
|
+
maxTotalBufferSize: 10 * 1024 * 1024,
|
|
4842
|
+
maxPostDataSize: 5 * 1024 * 1024
|
|
4843
|
+
}),
|
|
4844
|
+
ensureCdpDomain(client2, "Runtime"),
|
|
4845
|
+
ensureCdpDomain(client2, "Log")
|
|
4846
|
+
]);
|
|
4532
4847
|
}
|
|
4533
4848
|
|
|
4534
4849
|
// src/cdp-backend/discover.ts
|
|
@@ -4687,9 +5002,21 @@ var CdpSession = class {
|
|
|
4687
5002
|
} catch {
|
|
4688
5003
|
client2 = await CdpClient.connect(target.webSocketDebuggerUrl);
|
|
4689
5004
|
}
|
|
4690
|
-
|
|
4691
|
-
|
|
5005
|
+
let tabId;
|
|
5006
|
+
for (const [virtualId, registeredTargetId] of this.tabIdMap) {
|
|
5007
|
+
if (registeredTargetId === target.id) {
|
|
5008
|
+
tabId = virtualId;
|
|
5009
|
+
break;
|
|
5010
|
+
}
|
|
5011
|
+
}
|
|
5012
|
+
if (tabId === void 0) {
|
|
5013
|
+
tabId = this.nextTabId++;
|
|
5014
|
+
this.tabIdMap.set(tabId, target.id);
|
|
5015
|
+
}
|
|
5016
|
+
const buffers = createBuffers(tabId);
|
|
5017
|
+
await setupBufferListeners(client2, buffers);
|
|
4692
5018
|
const session = {
|
|
5019
|
+
tabId,
|
|
4693
5020
|
client: client2,
|
|
4694
5021
|
buffers,
|
|
4695
5022
|
targetId: target.id,
|
|
@@ -5945,6 +6272,143 @@ async function enrichCdpPageChangeSetWithRefs(session, observation) {
|
|
|
5945
6272
|
);
|
|
5946
6273
|
}
|
|
5947
6274
|
|
|
6275
|
+
// src/cdp-backend/request-handlers.ts
|
|
6276
|
+
function filterRequests(buffers, opts) {
|
|
6277
|
+
const pattern = opts.filter ? compileTextPattern(opts.filter) : void 0;
|
|
6278
|
+
return queryCapturedEntries(
|
|
6279
|
+
buffers.requests.filter(
|
|
6280
|
+
(request) => Number.isSafeInteger(request.captureSequence)
|
|
6281
|
+
),
|
|
6282
|
+
buffers.capture,
|
|
6283
|
+
{ after: opts.after, since: opts.since, limit: opts.count ?? 10 },
|
|
6284
|
+
(request) => (!opts.source || opts.source === "all" || request.source === opts.source) && (!pattern || matchesTextPattern(request.url, pattern) || matchesTextPattern(request.apiName, pattern)),
|
|
6285
|
+
buffers.capture.droppedRequestsThroughSequence,
|
|
6286
|
+
"requests"
|
|
6287
|
+
);
|
|
6288
|
+
}
|
|
6289
|
+
async function cdpGetRequests(session, data) {
|
|
6290
|
+
const opts = {
|
|
6291
|
+
count: data.count ?? 10,
|
|
6292
|
+
filter: data.filter,
|
|
6293
|
+
since: data.since,
|
|
6294
|
+
after: data.after,
|
|
6295
|
+
source: data.source,
|
|
6296
|
+
applyHiddenFilter: data.applyHiddenFilter !== false
|
|
6297
|
+
};
|
|
6298
|
+
const captured = filterRequests(session.buffers, opts);
|
|
6299
|
+
const serializeOpts = {
|
|
6300
|
+
includeBody: data.includeBody !== false,
|
|
6301
|
+
includeHeaders: data.includeHeaders === true,
|
|
6302
|
+
maxBodySize: data.maxBodySize ?? 5e4,
|
|
6303
|
+
fields: data.fields,
|
|
6304
|
+
keysOnly: data.keysOnly === true
|
|
6305
|
+
};
|
|
6306
|
+
return {
|
|
6307
|
+
meta: {
|
|
6308
|
+
count: captured.entries.length,
|
|
6309
|
+
totalMatched: captured.totalMatched,
|
|
6310
|
+
totalInBuffer: session.buffers.requests.length,
|
|
6311
|
+
filter: data.filter,
|
|
6312
|
+
since: data.since,
|
|
6313
|
+
after: data.after,
|
|
6314
|
+
nextCursor: captured.nextCursor,
|
|
6315
|
+
hasMore: captured.hasMore,
|
|
6316
|
+
gap: captured.gap,
|
|
6317
|
+
source: "cdp"
|
|
6318
|
+
},
|
|
6319
|
+
requests: captured.entries.map((r) => serializeRequest(r, serializeOpts))
|
|
6320
|
+
};
|
|
6321
|
+
}
|
|
6322
|
+
async function cdpGetLogs(session, data) {
|
|
6323
|
+
const { level, since, after, limit = 100, filter } = data;
|
|
6324
|
+
const pattern = filter ? compileTextPattern(filter) : void 0;
|
|
6325
|
+
const captured = queryCapturedEntries(
|
|
6326
|
+
session.buffers.logs,
|
|
6327
|
+
session.buffers.capture,
|
|
6328
|
+
{ after, since, limit },
|
|
6329
|
+
(log2) => (!level || level === "all" || log2.level === level) && (!pattern || matchesTextPattern(log2.message, pattern) || log2.args.some((arg) => matchesTextPattern(arg, pattern))),
|
|
6330
|
+
session.buffers.capture.droppedLogsThroughSequence,
|
|
6331
|
+
"logs"
|
|
6332
|
+
);
|
|
6333
|
+
const captureStatus = session.buffers.logs.length === 0 ? "armed" : "active";
|
|
6334
|
+
return {
|
|
6335
|
+
meta: {
|
|
6336
|
+
count: captured.entries.length,
|
|
6337
|
+
totalMatched: captured.totalMatched,
|
|
6338
|
+
totalInBuffer: session.buffers.logs.length,
|
|
6339
|
+
level: level || "all",
|
|
6340
|
+
since,
|
|
6341
|
+
after,
|
|
6342
|
+
filter,
|
|
6343
|
+
nextCursor: captured.nextCursor,
|
|
6344
|
+
hasMore: captured.hasMore,
|
|
6345
|
+
gap: captured.gap,
|
|
6346
|
+
captureStatus,
|
|
6347
|
+
...captureStatus === "armed" && {
|
|
6348
|
+
hint: "Log capture is active, but this tab has no captured history yet. Reload the current tab or repeat the triggering action, then call get_logs again."
|
|
6349
|
+
},
|
|
6350
|
+
source: "cdp"
|
|
6351
|
+
},
|
|
6352
|
+
logs: captured.entries
|
|
6353
|
+
};
|
|
6354
|
+
}
|
|
6355
|
+
async function cdpCaptureCheckpoint(session, _data) {
|
|
6356
|
+
return {
|
|
6357
|
+
tabId: session.tabId,
|
|
6358
|
+
cursor: captureCheckpoint(session.buffers.capture),
|
|
6359
|
+
timestampMs: Date.now(),
|
|
6360
|
+
captureStatus: session.buffers.capture.currentSequence === 0 ? "armed" : "active"
|
|
6361
|
+
};
|
|
6362
|
+
}
|
|
6363
|
+
async function collectCdpPageDiagnostics(session, after, diagnostics) {
|
|
6364
|
+
const result = {};
|
|
6365
|
+
if (diagnostics.logs) {
|
|
6366
|
+
const options = diagnostics.logs === true ? { level: "error", limit: 100 } : { level: "error", limit: 100, ...diagnostics.logs };
|
|
6367
|
+
result.logs = await cdpGetLogs(session, { ...options, after });
|
|
6368
|
+
}
|
|
6369
|
+
if (diagnostics.requests) {
|
|
6370
|
+
const options = diagnostics.requests === true ? { source: "all", includeBody: false, count: 100 } : {
|
|
6371
|
+
source: "all",
|
|
6372
|
+
includeBody: false,
|
|
6373
|
+
count: 100,
|
|
6374
|
+
...diagnostics.requests
|
|
6375
|
+
};
|
|
6376
|
+
result.requests = await cdpGetRequests(session, { ...options, after });
|
|
6377
|
+
}
|
|
6378
|
+
return result;
|
|
6379
|
+
}
|
|
6380
|
+
async function cdpGetEvents(session, data) {
|
|
6381
|
+
const { source = "all", event_type, since, limit = 20, filter, includeRaw = false } = data;
|
|
6382
|
+
const response = queryTrackingEvents(session.buffers.events, {
|
|
6383
|
+
source,
|
|
6384
|
+
event_type,
|
|
6385
|
+
since,
|
|
6386
|
+
limit,
|
|
6387
|
+
filter
|
|
6388
|
+
});
|
|
6389
|
+
const captureStatus = response.totalInBuffer === 0 ? "armed" : "active";
|
|
6390
|
+
const hint = response.events.length === 0 && captureStatus === "armed" ? TRACKING_CAPTURE_ARMED_HINT : void 0;
|
|
6391
|
+
return {
|
|
6392
|
+
meta: {
|
|
6393
|
+
count: response.events.length,
|
|
6394
|
+
totalMatched: response.totalMatched,
|
|
6395
|
+
totalInBuffer: response.totalInBuffer,
|
|
6396
|
+
source,
|
|
6397
|
+
captureStatus,
|
|
6398
|
+
captureSource: "cdp",
|
|
6399
|
+
includeRaw,
|
|
6400
|
+
hint
|
|
6401
|
+
},
|
|
6402
|
+
events: response.events.map((event) => formatTrackingEvent(event, includeRaw))
|
|
6403
|
+
};
|
|
6404
|
+
}
|
|
6405
|
+
registerActions([
|
|
6406
|
+
{ name: "capture_checkpoint", session: "page", handler: cdpCaptureCheckpoint },
|
|
6407
|
+
{ name: "get_requests", session: "page", handler: cdpGetRequests },
|
|
6408
|
+
{ name: "get_logs", session: "page", handler: cdpGetLogs },
|
|
6409
|
+
{ name: "get_events", session: "page", handler: cdpGetEvents }
|
|
6410
|
+
]);
|
|
6411
|
+
|
|
5948
6412
|
// src/cdp-backend/composite-handlers.ts
|
|
5949
6413
|
async function cdpRunActions(session, data, controlSource = "local") {
|
|
5950
6414
|
const { actions, tabId } = data;
|
|
@@ -6020,21 +6484,42 @@ async function cdpRunActions(session, data, controlSource = "local") {
|
|
|
6020
6484
|
};
|
|
6021
6485
|
}
|
|
6022
6486
|
async function cdpObservedPageAction(session, action, data, controlSource = "local") {
|
|
6023
|
-
const { actionData, observe } = splitObservedActionPayload(data);
|
|
6024
|
-
if (observe === false) {
|
|
6025
|
-
return dispatchCdpAction(session, action, actionData, controlSource);
|
|
6026
|
-
}
|
|
6487
|
+
const { actionData, observe, diagnostics } = splitObservedActionPayload(action, data);
|
|
6027
6488
|
const { tabId } = actionData;
|
|
6028
6489
|
if (typeof tabId !== "number") throw new Error(`${action} requires a numeric tabId`);
|
|
6029
6490
|
const pageSession = await session.getPageSession(tabId);
|
|
6030
6491
|
await ensureControlledIndicator(pageSession, controlSource);
|
|
6031
|
-
|
|
6492
|
+
if (observe === false) {
|
|
6493
|
+
if (!diagnostics) return dispatchCdpAction(session, action, actionData, controlSource);
|
|
6494
|
+
const cursor = captureCheckpoint(pageSession.buffers.capture);
|
|
6495
|
+
let actionResult;
|
|
6496
|
+
let actionError;
|
|
6497
|
+
try {
|
|
6498
|
+
actionResult = await dispatchCdpAction(session, action, actionData, controlSource);
|
|
6499
|
+
} catch (error48) {
|
|
6500
|
+
actionError = error48 instanceof Error ? error48.message : String(error48);
|
|
6501
|
+
}
|
|
6502
|
+
return {
|
|
6503
|
+
action: {
|
|
6504
|
+
name: action,
|
|
6505
|
+
success: actionError === void 0,
|
|
6506
|
+
...actionResult !== void 0 ? { data: actionResult } : {},
|
|
6507
|
+
...actionError ? { error: actionError } : {}
|
|
6508
|
+
},
|
|
6509
|
+
diagnostics: await collectCdpPageDiagnostics(pageSession, cursor, diagnostics)
|
|
6510
|
+
};
|
|
6511
|
+
}
|
|
6512
|
+
let diagnosticsCursor;
|
|
6513
|
+
const result = await runPageAct(
|
|
6032
6514
|
{ action, actionData, observe },
|
|
6033
6515
|
{
|
|
6034
6516
|
startObservation: () => startPageObservation(pageSession),
|
|
6035
6517
|
finishObservation: (checkpoint, options) => finishPageObservation(pageSession, checkpoint, options),
|
|
6036
6518
|
startNavigationObserver: (options) => startCdpNavigationObserver(session, pageSession, options.urlBefore, options),
|
|
6037
|
-
executeAction: (name, params) =>
|
|
6519
|
+
executeAction: (name, params) => {
|
|
6520
|
+
if (diagnostics) diagnosticsCursor = captureCheckpoint(pageSession.buffers.capture);
|
|
6521
|
+
return dispatchCdpAction(session, name, { ...params, tabId }, controlSource);
|
|
6522
|
+
},
|
|
6038
6523
|
finalizeObservation: (observation) => {
|
|
6039
6524
|
if (observation.mode === "delta") {
|
|
6040
6525
|
return enrichCdpPageChangeSetWithRefs(pageSession, observation);
|
|
@@ -6044,6 +6529,11 @@ async function cdpObservedPageAction(session, action, data, controlSource = "loc
|
|
|
6044
6529
|
disposeObservation: () => disposePageObservation(pageSession)
|
|
6045
6530
|
}
|
|
6046
6531
|
);
|
|
6532
|
+
if (!diagnostics || !diagnosticsCursor) return result;
|
|
6533
|
+
return {
|
|
6534
|
+
...result,
|
|
6535
|
+
diagnostics: await collectCdpPageDiagnostics(pageSession, diagnosticsCursor, diagnostics)
|
|
6536
|
+
};
|
|
6047
6537
|
}
|
|
6048
6538
|
registerActions([{ name: "run_actions", session: "browser", handler: cdpRunActions }]);
|
|
6049
6539
|
|
|
@@ -6631,112 +7121,6 @@ function listCloudConnectors() {
|
|
|
6631
7121
|
return { connectors: pushIfChanged() };
|
|
6632
7122
|
}
|
|
6633
7123
|
|
|
6634
|
-
// src/cdp-backend/request-handlers.ts
|
|
6635
|
-
function filterRequests(buffers, opts) {
|
|
6636
|
-
let requests = [...buffers.requests];
|
|
6637
|
-
if (opts.since !== void 0) {
|
|
6638
|
-
requests = requests.filter((r) => r.timestampMs >= opts.since);
|
|
6639
|
-
}
|
|
6640
|
-
if (opts.filter) {
|
|
6641
|
-
const pattern = compileTextPattern(opts.filter);
|
|
6642
|
-
requests = requests.filter(
|
|
6643
|
-
(r) => matchesTextPattern(r.url, pattern) || matchesTextPattern(r.apiName, pattern)
|
|
6644
|
-
);
|
|
6645
|
-
}
|
|
6646
|
-
if (opts.source === "mtop") {
|
|
6647
|
-
requests = requests.filter((r) => r.url?.includes("/h5/") || r.url?.includes("mtop"));
|
|
6648
|
-
}
|
|
6649
|
-
const count = opts.count ?? 10;
|
|
6650
|
-
return {
|
|
6651
|
-
requests: requests.slice(-count),
|
|
6652
|
-
totalMatched: requests.length
|
|
6653
|
-
};
|
|
6654
|
-
}
|
|
6655
|
-
async function cdpGetRequests(session, data) {
|
|
6656
|
-
const opts = {
|
|
6657
|
-
count: data.count ?? 10,
|
|
6658
|
-
filter: data.filter,
|
|
6659
|
-
since: data.since,
|
|
6660
|
-
source: data.source,
|
|
6661
|
-
applyHiddenFilter: data.applyHiddenFilter !== false
|
|
6662
|
-
};
|
|
6663
|
-
const { requests, totalMatched } = filterRequests(session.buffers, opts);
|
|
6664
|
-
const serializeOpts = {
|
|
6665
|
-
includeBody: data.includeBody !== false,
|
|
6666
|
-
includeHeaders: data.includeHeaders === true,
|
|
6667
|
-
maxBodySize: data.maxBodySize ?? 5e4,
|
|
6668
|
-
fields: data.fields,
|
|
6669
|
-
keysOnly: data.keysOnly === true
|
|
6670
|
-
};
|
|
6671
|
-
return {
|
|
6672
|
-
meta: {
|
|
6673
|
-
count: requests.length,
|
|
6674
|
-
totalMatched,
|
|
6675
|
-
totalInBuffer: session.buffers.requests.length,
|
|
6676
|
-
filter: data.filter,
|
|
6677
|
-
since: data.since,
|
|
6678
|
-
source: "cdp"
|
|
6679
|
-
},
|
|
6680
|
-
requests: requests.map((r) => serializeRequest(r, serializeOpts))
|
|
6681
|
-
};
|
|
6682
|
-
}
|
|
6683
|
-
async function cdpGetLogs(session, data) {
|
|
6684
|
-
const { level, since, limit = 100, filter } = data;
|
|
6685
|
-
let logs = [...session.buffers.logs];
|
|
6686
|
-
if (since !== void 0) {
|
|
6687
|
-
logs = logs.filter((l) => l.timestamp >= since);
|
|
6688
|
-
}
|
|
6689
|
-
if (level && level !== "all") {
|
|
6690
|
-
logs = logs.filter((l) => l.level === level);
|
|
6691
|
-
}
|
|
6692
|
-
if (filter) {
|
|
6693
|
-
const f = filter.toLowerCase();
|
|
6694
|
-
logs = logs.filter((l) => l.message?.toLowerCase().includes(f));
|
|
6695
|
-
}
|
|
6696
|
-
logs = logs.slice(-limit);
|
|
6697
|
-
return {
|
|
6698
|
-
meta: {
|
|
6699
|
-
count: logs.length,
|
|
6700
|
-
totalMatched: logs.length,
|
|
6701
|
-
level: level || "all",
|
|
6702
|
-
since,
|
|
6703
|
-
filter,
|
|
6704
|
-
source: "cdp"
|
|
6705
|
-
},
|
|
6706
|
-
logs
|
|
6707
|
-
};
|
|
6708
|
-
}
|
|
6709
|
-
async function cdpGetEvents(session, data) {
|
|
6710
|
-
const { source = "all", event_type, since, limit = 20, filter, includeRaw = false } = data;
|
|
6711
|
-
const response = queryTrackingEvents(session.buffers.events, {
|
|
6712
|
-
source,
|
|
6713
|
-
event_type,
|
|
6714
|
-
since,
|
|
6715
|
-
limit,
|
|
6716
|
-
filter
|
|
6717
|
-
});
|
|
6718
|
-
const captureStatus = response.totalInBuffer === 0 ? "armed" : "active";
|
|
6719
|
-
const hint = response.events.length === 0 && captureStatus === "armed" ? TRACKING_CAPTURE_ARMED_HINT : void 0;
|
|
6720
|
-
return {
|
|
6721
|
-
meta: {
|
|
6722
|
-
count: response.events.length,
|
|
6723
|
-
totalMatched: response.totalMatched,
|
|
6724
|
-
totalInBuffer: response.totalInBuffer,
|
|
6725
|
-
source,
|
|
6726
|
-
captureStatus,
|
|
6727
|
-
captureSource: "cdp",
|
|
6728
|
-
includeRaw,
|
|
6729
|
-
hint
|
|
6730
|
-
},
|
|
6731
|
-
events: response.events.map((event) => formatTrackingEvent(event, includeRaw))
|
|
6732
|
-
};
|
|
6733
|
-
}
|
|
6734
|
-
registerActions([
|
|
6735
|
-
{ name: "get_requests", session: "page", handler: cdpGetRequests },
|
|
6736
|
-
{ name: "get_logs", session: "page", handler: cdpGetLogs },
|
|
6737
|
-
{ name: "get_events", session: "page", handler: cdpGetEvents }
|
|
6738
|
-
]);
|
|
6739
|
-
|
|
6740
7124
|
// src/cdp-backend/send-request.ts
|
|
6741
7125
|
import { readFile } from "node:fs/promises";
|
|
6742
7126
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -6746,6 +7130,10 @@ function setHeader(headers, name, value) {
|
|
|
6746
7130
|
if (existing && existing !== name) delete headers[existing];
|
|
6747
7131
|
headers[name] = value;
|
|
6748
7132
|
}
|
|
7133
|
+
function removeHeader(headers, name) {
|
|
7134
|
+
const existing = findSendRequestHeaderName(headers, name);
|
|
7135
|
+
if (existing) delete headers[existing];
|
|
7136
|
+
}
|
|
6749
7137
|
function escapeMultipartQuotedValue(value) {
|
|
6750
7138
|
return value.replace(/\\/g, "\\\\").replace(/"/g, "%22");
|
|
6751
7139
|
}
|
|
@@ -6854,10 +7242,19 @@ async function executeNodeSendRequest(data, cookieMap = /* @__PURE__ */ new Map(
|
|
|
6854
7242
|
Accept: "application/json, text/plain, */*",
|
|
6855
7243
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
|
6856
7244
|
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
|
6857
|
-
Referer: targetUrl.origin + "/mearl",
|
|
6858
|
-
Origin: targetUrl.origin,
|
|
6859
7245
|
...headers
|
|
6860
7246
|
};
|
|
7247
|
+
const resolvedSourceHeaders = getSendRequestSourceHeaders(targetUrl, headers);
|
|
7248
|
+
if (resolvedSourceHeaders.referer) {
|
|
7249
|
+
setHeader(requestHeaders, "Referer", resolvedSourceHeaders.referer);
|
|
7250
|
+
} else {
|
|
7251
|
+
removeHeader(requestHeaders, "Referer");
|
|
7252
|
+
}
|
|
7253
|
+
if (resolvedSourceHeaders.origin) {
|
|
7254
|
+
setHeader(requestHeaders, "Origin", resolvedSourceHeaders.origin);
|
|
7255
|
+
} else {
|
|
7256
|
+
removeHeader(requestHeaders, "Origin");
|
|
7257
|
+
}
|
|
6861
7258
|
const cookieHeader = [...cookieMap.entries()].map(([key, value]) => `${key}=${value}`).join("; ");
|
|
6862
7259
|
if (cookieHeader) setHeader(requestHeaders, "Cookie", cookieHeader);
|
|
6863
7260
|
const xsrfToken = cookieMap.get("XSRF-TOKEN");
|
|
@@ -7215,8 +7612,8 @@ registerActions([
|
|
|
7215
7612
|
]);
|
|
7216
7613
|
|
|
7217
7614
|
// src/cdp-backend/tdbank-handlers.ts
|
|
7218
|
-
async function cdpFetchTdbank(session,
|
|
7219
|
-
const url2 = new URL(`https://tdbank.alibaba-inc.com${
|
|
7615
|
+
async function cdpFetchTdbank(session, path13, options = {}) {
|
|
7616
|
+
const url2 = new URL(`https://tdbank.alibaba-inc.com${path13}`);
|
|
7220
7617
|
for (const [key, value] of Object.entries(options.params ?? {})) {
|
|
7221
7618
|
if (value !== void 0 && value !== null) {
|
|
7222
7619
|
url2.searchParams.set(key, String(value));
|
|
@@ -7484,6 +7881,14 @@ async function cdpTdbankAccount(cdpSession2, data) {
|
|
|
7484
7881
|
registerActions([{ name: "tdbank_account", session: "browser", handler: cdpTdbankAccount }]);
|
|
7485
7882
|
|
|
7486
7883
|
// src/cdp-backend/tab-handlers.ts
|
|
7884
|
+
function currentCapture(pageSession) {
|
|
7885
|
+
return {
|
|
7886
|
+
tabId: pageSession.tabId,
|
|
7887
|
+
cursor: captureCheckpoint(pageSession.buffers.capture),
|
|
7888
|
+
timestampMs: Date.now(),
|
|
7889
|
+
captureStatus: pageSession.buffers.capture.currentSequence === 0 ? "armed" : "active"
|
|
7890
|
+
};
|
|
7891
|
+
}
|
|
7487
7892
|
async function cdpTabOpen(session, data, controlSource = "local") {
|
|
7488
7893
|
const { url: url2, active = false, emulation, reuse = "never", match } = data;
|
|
7489
7894
|
if (!url2 || typeof url2 !== "string") {
|
|
@@ -7510,12 +7915,14 @@ async function cdpTabOpen(session, data, controlSource = "local") {
|
|
|
7510
7915
|
const tabId2 = await session.ensureTargetRegistered(existing.targetId);
|
|
7511
7916
|
const pageSession2 = await session.getPageSession(tabId2);
|
|
7512
7917
|
await ensureControlledIndicator(pageSession2, controlSource);
|
|
7918
|
+
const capture2 = currentCapture(pageSession2);
|
|
7513
7919
|
return {
|
|
7514
7920
|
tabId: tabId2,
|
|
7515
7921
|
url: existing.url ?? url2,
|
|
7516
7922
|
title: existing.title ?? "",
|
|
7517
7923
|
opened: false,
|
|
7518
|
-
reused: true
|
|
7924
|
+
reused: true,
|
|
7925
|
+
capture: capture2
|
|
7519
7926
|
};
|
|
7520
7927
|
}
|
|
7521
7928
|
if (reuse === "require") {
|
|
@@ -7530,6 +7937,7 @@ async function cdpTabOpen(session, data, controlSource = "local") {
|
|
|
7530
7937
|
const tabId = await session.registerTarget(targetId);
|
|
7531
7938
|
const pageSession = await session.getPageSession(tabId);
|
|
7532
7939
|
await ensureControlledIndicator(pageSession, controlSource);
|
|
7940
|
+
const capture = currentCapture(pageSession);
|
|
7533
7941
|
if (emulationConfig) {
|
|
7534
7942
|
for (const { method, params } of buildEnableEmulationCommands(emulationConfig)) {
|
|
7535
7943
|
await pageSession.client.sendCommand(method, params);
|
|
@@ -7548,6 +7956,7 @@ async function cdpTabOpen(session, data, controlSource = "local") {
|
|
|
7548
7956
|
title: targetInfo?.title ?? "",
|
|
7549
7957
|
opened: true,
|
|
7550
7958
|
reused: false,
|
|
7959
|
+
capture,
|
|
7551
7960
|
...emulationConfig && {
|
|
7552
7961
|
emulation: {
|
|
7553
7962
|
preset: emulationConfig.presetName,
|
|
@@ -8506,12 +8915,9 @@ async function getViewportBackendNodeIds(session) {
|
|
|
8506
8915
|
includePaintOrder: false
|
|
8507
8916
|
})
|
|
8508
8917
|
]);
|
|
8509
|
-
const viewport = metrics
|
|
8510
|
-
|
|
8511
|
-
const top = viewport
|
|
8512
|
-
const width = viewport?.clientWidth;
|
|
8513
|
-
const height = viewport?.clientHeight;
|
|
8514
|
-
if (!width || !height) throw new Error("page_snapshot: viewport metrics are unavailable");
|
|
8918
|
+
const viewport = resolveDOMSnapshotViewportBounds(metrics);
|
|
8919
|
+
if (!viewport) throw new Error("page_snapshot: viewport metrics are unavailable");
|
|
8920
|
+
const { left, top, width, height } = viewport;
|
|
8515
8921
|
const right = left + width;
|
|
8516
8922
|
const bottom = top + height;
|
|
8517
8923
|
const visible = /* @__PURE__ */ new Set();
|
|
@@ -9346,7 +9752,7 @@ import os2 from "node:os";
|
|
|
9346
9752
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9347
9753
|
|
|
9348
9754
|
// src/version.ts
|
|
9349
|
-
var NATIVE_HOST_VERSION = true ? "2.
|
|
9755
|
+
var NATIVE_HOST_VERSION = true ? "2.3.0" : "unknown";
|
|
9350
9756
|
|
|
9351
9757
|
// src/analytics.ts
|
|
9352
9758
|
var MEASUREMENT_ID = "G-W84LJDZ6PH";
|
|
@@ -10207,17 +10613,51 @@ var AgentChatManager = class {
|
|
|
10207
10613
|
|
|
10208
10614
|
// src/agent/codex-provider.ts
|
|
10209
10615
|
import os3 from "node:os";
|
|
10210
|
-
import path7 from "node:path";
|
|
10211
10616
|
import readline from "node:readline";
|
|
10212
|
-
import { spawn as
|
|
10617
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
10213
10618
|
|
|
10214
10619
|
// src/agent/executable-resolver.ts
|
|
10215
|
-
import
|
|
10216
|
-
import { spawn as
|
|
10620
|
+
import fs6 from "node:fs";
|
|
10621
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
10622
|
+
import path7 from "node:path";
|
|
10217
10623
|
|
|
10218
|
-
//
|
|
10624
|
+
// ../setup/dist/process.js
|
|
10625
|
+
import fs5 from "node:fs";
|
|
10219
10626
|
import path6 from "node:path";
|
|
10220
|
-
|
|
10627
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
10628
|
+
function isExecutable(filePath, platform = process.platform) {
|
|
10629
|
+
try {
|
|
10630
|
+
fs5.accessSync(filePath, platform === "win32" ? fs5.constants.F_OK : fs5.constants.X_OK);
|
|
10631
|
+
return true;
|
|
10632
|
+
} catch {
|
|
10633
|
+
return false;
|
|
10634
|
+
}
|
|
10635
|
+
}
|
|
10636
|
+
function executableNames(name, platform = process.platform) {
|
|
10637
|
+
return platform === "win32" ? [`${name}.cmd`, `${name}.exe`, name] : [name];
|
|
10638
|
+
}
|
|
10639
|
+
function versionManagerExecutableCandidates(home, names, options = {}) {
|
|
10640
|
+
const env = options.env ?? process.env;
|
|
10641
|
+
const platform = options.platform ?? process.platform;
|
|
10642
|
+
const readdirSync2 = options.readdirSync ?? fs5.readdirSync;
|
|
10643
|
+
const fnmDefaultRoot = env.XDG_DATA_HOME ? path6.join(env.XDG_DATA_HOME, "fnm") : platform === "darwin" ? path6.join(home, "Library", "Application Support", "fnm") : platform === "win32" && env.APPDATA ? path6.join(env.APPDATA, "fnm") : path6.join(home, ".local", "share", "fnm");
|
|
10644
|
+
const roots = [
|
|
10645
|
+
path6.join(env.NVM_DIR || path6.join(home, ".nvm"), "versions", "node"),
|
|
10646
|
+
path6.join(env.FNM_DIR || fnmDefaultRoot, "node-versions"),
|
|
10647
|
+
path6.join(home, ".fnm", "node-versions")
|
|
10648
|
+
].filter((root, index, all) => all.indexOf(root) === index);
|
|
10649
|
+
return roots.flatMap((root) => {
|
|
10650
|
+
try {
|
|
10651
|
+
return readdirSync2(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((left, right) => right.name.localeCompare(left.name, void 0, { numeric: true })).flatMap((entry) => names.flatMap((name) => [
|
|
10652
|
+
path6.join(root, entry.name, "bin", name),
|
|
10653
|
+
path6.join(root, entry.name, "installation", "bin", name)
|
|
10654
|
+
]));
|
|
10655
|
+
} catch {
|
|
10656
|
+
return [];
|
|
10657
|
+
}
|
|
10658
|
+
});
|
|
10659
|
+
}
|
|
10660
|
+
function resolveSpawnCommand(executable, args, platform = process.platform, commandInterpreter = process.env.ComSpec) {
|
|
10221
10661
|
if (platform === "win32" && /\.(?:cmd|bat)$/i.test(executable)) {
|
|
10222
10662
|
return {
|
|
10223
10663
|
command: commandInterpreter || "cmd.exe",
|
|
@@ -10226,16 +10666,64 @@ function agentSpawnCommand(executable, args, platform = process.platform, comman
|
|
|
10226
10666
|
}
|
|
10227
10667
|
return { command: executable, args };
|
|
10228
10668
|
}
|
|
10229
|
-
function
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
|
|
10233
|
-
|
|
10234
|
-
|
|
10235
|
-
return
|
|
10669
|
+
function prependCommandPath(command, env = process.env) {
|
|
10670
|
+
if (!path6.isAbsolute(command))
|
|
10671
|
+
return env;
|
|
10672
|
+
return prependPath(path6.dirname(command), env);
|
|
10673
|
+
}
|
|
10674
|
+
function prependNodePath(env = process.env, nodeExecutable = process.execPath) {
|
|
10675
|
+
return prependPath(path6.dirname(nodeExecutable), env);
|
|
10676
|
+
}
|
|
10677
|
+
function prependPath(directory, env) {
|
|
10678
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
10679
|
+
const inherited = env[pathKey] || "";
|
|
10680
|
+
const entries = inherited.split(path6.delimiter).filter(Boolean);
|
|
10681
|
+
if (entries.includes(directory))
|
|
10682
|
+
return env;
|
|
10683
|
+
return { ...env, [pathKey]: [directory, ...entries].join(path6.delimiter) };
|
|
10236
10684
|
}
|
|
10237
10685
|
|
|
10238
10686
|
// src/agent/executable-resolver.ts
|
|
10687
|
+
function agentExecutableCandidatePaths({
|
|
10688
|
+
executableNames: executableNames2,
|
|
10689
|
+
configuredPath,
|
|
10690
|
+
env = process.env,
|
|
10691
|
+
extraUserCandidates = [],
|
|
10692
|
+
home,
|
|
10693
|
+
platform = process.platform,
|
|
10694
|
+
processExecPath = process.execPath,
|
|
10695
|
+
readdirSync: readdirSync2
|
|
10696
|
+
}) {
|
|
10697
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
10698
|
+
const pathCandidates = (env[pathKey] || "").split(path7.delimiter).filter(Boolean).flatMap((directory) => executableNames2.map((name) => path7.join(directory, name)));
|
|
10699
|
+
const commonUserDirectories = [
|
|
10700
|
+
path7.join(home, ".local", "bin"),
|
|
10701
|
+
path7.join(home, ".npm-global", "bin"),
|
|
10702
|
+
path7.join(home, ".volta", "bin"),
|
|
10703
|
+
path7.join(home, ".local", "share", "pnpm"),
|
|
10704
|
+
path7.join(home, "Library", "pnpm"),
|
|
10705
|
+
path7.join(home, ".bun", "bin"),
|
|
10706
|
+
...platform === "win32" && env.APPDATA ? [path7.join(env.APPDATA, "npm")] : []
|
|
10707
|
+
];
|
|
10708
|
+
const systemDirectories = platform === "win32" ? [] : ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin"];
|
|
10709
|
+
return [
|
|
10710
|
+
configuredPath,
|
|
10711
|
+
...executableNames2.map((name) => path7.join(path7.dirname(processExecPath), name)),
|
|
10712
|
+
...commonUserDirectories.flatMap(
|
|
10713
|
+
(directory) => executableNames2.map((name) => path7.join(directory, name))
|
|
10714
|
+
),
|
|
10715
|
+
...extraUserCandidates,
|
|
10716
|
+
...versionManagerExecutableCandidates(home, executableNames2, {
|
|
10717
|
+
env,
|
|
10718
|
+
platform,
|
|
10719
|
+
readdirSync: readdirSync2
|
|
10720
|
+
}),
|
|
10721
|
+
...systemDirectories.flatMap(
|
|
10722
|
+
(directory) => executableNames2.map((name) => path7.join(directory, name))
|
|
10723
|
+
),
|
|
10724
|
+
...pathCandidates
|
|
10725
|
+
].filter((candidate) => typeof candidate === "string");
|
|
10726
|
+
}
|
|
10239
10727
|
var AgentExecutableResolver = class {
|
|
10240
10728
|
constructor(options) {
|
|
10241
10729
|
this.options = options;
|
|
@@ -10306,11 +10794,11 @@ function probeAgentExecutable(executable, options) {
|
|
|
10306
10794
|
return new Promise((resolve) => {
|
|
10307
10795
|
let settled = false;
|
|
10308
10796
|
let stderr = "";
|
|
10309
|
-
const launch =
|
|
10310
|
-
const child =
|
|
10797
|
+
const launch = resolveSpawnCommand(executable, options.args);
|
|
10798
|
+
const child = spawn5(launch.command, launch.args, {
|
|
10311
10799
|
stdio: ["ignore", "ignore", "pipe"],
|
|
10312
10800
|
windowsHide: true,
|
|
10313
|
-
env:
|
|
10801
|
+
env: prependNodePath()
|
|
10314
10802
|
});
|
|
10315
10803
|
const finish = (error48) => {
|
|
10316
10804
|
if (settled) return;
|
|
@@ -10337,8 +10825,8 @@ function probeAgentExecutable(executable, options) {
|
|
|
10337
10825
|
}
|
|
10338
10826
|
function isExecutableFile(candidate) {
|
|
10339
10827
|
try {
|
|
10340
|
-
|
|
10341
|
-
return
|
|
10828
|
+
fs6.accessSync(candidate, process.platform === "win32" ? fs6.constants.F_OK : fs6.constants.X_OK);
|
|
10829
|
+
return fs6.statSync(candidate).isFile();
|
|
10342
10830
|
} catch {
|
|
10343
10831
|
return false;
|
|
10344
10832
|
}
|
|
@@ -10349,6 +10837,21 @@ var REQUEST_TIMEOUT_MS = 3e4;
|
|
|
10349
10837
|
var PROBE_TIMEOUT_MS = 5e3;
|
|
10350
10838
|
var MAX_MODEL_CHARS = 256;
|
|
10351
10839
|
var CODEX_NOT_FOUND_ERROR = "Codex CLI was not found. Install @openai/codex or set MEARL_CODEX_PATH.";
|
|
10840
|
+
function codexExecutableCandidatePaths(options = {}) {
|
|
10841
|
+
const env = options.env ?? process.env;
|
|
10842
|
+
const home = (options.homedir ?? os3.homedir)();
|
|
10843
|
+
const platform = options.platform ?? process.platform;
|
|
10844
|
+
const executableName = platform === "win32" ? "codex.cmd" : "codex";
|
|
10845
|
+
return agentExecutableCandidatePaths({
|
|
10846
|
+
executableNames: [executableName],
|
|
10847
|
+
configuredPath: env.MEARL_CODEX_PATH,
|
|
10848
|
+
env,
|
|
10849
|
+
home,
|
|
10850
|
+
platform,
|
|
10851
|
+
processExecPath: options.processExecPath,
|
|
10852
|
+
readdirSync: options.readdirSync
|
|
10853
|
+
});
|
|
10854
|
+
}
|
|
10352
10855
|
function codexModelInfo(value) {
|
|
10353
10856
|
if (typeof value !== "string") return void 0;
|
|
10354
10857
|
const id = value.trim().slice(0, MAX_MODEL_CHARS);
|
|
@@ -10433,7 +10936,7 @@ function externalOpenCommand(url2, platform = process.platform) {
|
|
|
10433
10936
|
function openExternalUrl(url2) {
|
|
10434
10937
|
const { command, args } = externalOpenCommand(url2);
|
|
10435
10938
|
return new Promise((resolve, reject) => {
|
|
10436
|
-
const child =
|
|
10939
|
+
const child = spawn6(command, args, { stdio: "ignore", windowsHide: true });
|
|
10437
10940
|
child.once("error", (error48) => {
|
|
10438
10941
|
reject(new Error(`Unable to open Codex App: ${error48.message}`));
|
|
10439
10942
|
});
|
|
@@ -10664,10 +11167,10 @@ var CodexAgentProvider = class {
|
|
|
10664
11167
|
throw new Error(resolution.error);
|
|
10665
11168
|
}
|
|
10666
11169
|
const { executable } = resolution;
|
|
10667
|
-
const launch =
|
|
10668
|
-
const childEnv =
|
|
11170
|
+
const launch = resolveSpawnCommand(executable, ["app-server", "--listen", "stdio://"]);
|
|
11171
|
+
const childEnv = prependNodePath();
|
|
10669
11172
|
if (this.mearlSocketPath) childEnv.MEARL_SOCKET_PATH = this.mearlSocketPath;
|
|
10670
|
-
const child =
|
|
11173
|
+
const child = spawn6(launch.command, launch.args, {
|
|
10671
11174
|
stdio: ["pipe", "pipe", "pipe"],
|
|
10672
11175
|
windowsHide: true,
|
|
10673
11176
|
env: childEnv
|
|
@@ -10830,26 +11333,15 @@ var CodexAgentProvider = class {
|
|
|
10830
11333
|
return this.executableResolver.resolve();
|
|
10831
11334
|
}
|
|
10832
11335
|
resolveExecutableCandidates() {
|
|
10833
|
-
|
|
10834
|
-
const configured = process.env.MEARL_CODEX_PATH;
|
|
10835
|
-
const pathCandidates = (process.env.PATH || "").split(path7.delimiter).filter(Boolean).map((dir) => path7.join(dir, executableName));
|
|
10836
|
-
return executableFileCandidates([
|
|
10837
|
-
configured,
|
|
10838
|
-
path7.join(path7.dirname(process.execPath), executableName),
|
|
10839
|
-
path7.join(os3.homedir(), ".local", "bin", executableName),
|
|
10840
|
-
path7.join(os3.homedir(), ".npm-global", "bin", executableName),
|
|
10841
|
-
path7.join(os3.homedir(), ".volta", "bin", executableName),
|
|
10842
|
-
...process.platform === "win32" ? [] : ["/opt/homebrew/bin/codex", "/usr/local/bin/codex", "/usr/bin/codex"],
|
|
10843
|
-
...pathCandidates
|
|
10844
|
-
]);
|
|
11336
|
+
return executableFileCandidates(codexExecutableCandidatePaths());
|
|
10845
11337
|
}
|
|
10846
11338
|
};
|
|
10847
11339
|
|
|
10848
11340
|
// src/agent/qoder-provider.ts
|
|
10849
|
-
import
|
|
11341
|
+
import fs7 from "node:fs";
|
|
10850
11342
|
import os4 from "node:os";
|
|
10851
11343
|
import path8 from "node:path";
|
|
10852
|
-
import { spawn as
|
|
11344
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
10853
11345
|
import { Readable, Writable } from "node:stream";
|
|
10854
11346
|
|
|
10855
11347
|
// ../../node_modules/.pnpm/@agentclientprotocol+sdk@1.2.1_zod@4.3.6/node_modules/@agentclientprotocol/sdk/dist/schema/index.js
|
|
@@ -11671,10 +12163,10 @@ function mergeDefs(...defs) {
|
|
|
11671
12163
|
function cloneDef(schema) {
|
|
11672
12164
|
return mergeDefs(schema._zod.def);
|
|
11673
12165
|
}
|
|
11674
|
-
function getElementAtPath(obj,
|
|
11675
|
-
if (!
|
|
12166
|
+
function getElementAtPath(obj, path13) {
|
|
12167
|
+
if (!path13)
|
|
11676
12168
|
return obj;
|
|
11677
|
-
return
|
|
12169
|
+
return path13.reduce((acc, key) => acc?.[key], obj);
|
|
11678
12170
|
}
|
|
11679
12171
|
function promiseAllObject(promisesObj) {
|
|
11680
12172
|
const keys = Object.keys(promisesObj);
|
|
@@ -12057,11 +12549,11 @@ function aborted(x, startIndex = 0) {
|
|
|
12057
12549
|
}
|
|
12058
12550
|
return false;
|
|
12059
12551
|
}
|
|
12060
|
-
function prefixIssues(
|
|
12552
|
+
function prefixIssues(path13, issues) {
|
|
12061
12553
|
return issues.map((iss) => {
|
|
12062
12554
|
var _a2;
|
|
12063
12555
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
12064
|
-
iss.path.unshift(
|
|
12556
|
+
iss.path.unshift(path13);
|
|
12065
12557
|
return iss;
|
|
12066
12558
|
});
|
|
12067
12559
|
}
|
|
@@ -12244,7 +12736,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
12244
12736
|
}
|
|
12245
12737
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
12246
12738
|
const result = { errors: [] };
|
|
12247
|
-
const processError = (error49,
|
|
12739
|
+
const processError = (error49, path13 = []) => {
|
|
12248
12740
|
var _a2, _b;
|
|
12249
12741
|
for (const issue2 of error49.issues) {
|
|
12250
12742
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -12254,7 +12746,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
12254
12746
|
} else if (issue2.code === "invalid_element") {
|
|
12255
12747
|
processError({ issues: issue2.issues }, issue2.path);
|
|
12256
12748
|
} else {
|
|
12257
|
-
const fullpath = [...
|
|
12749
|
+
const fullpath = [...path13, ...issue2.path];
|
|
12258
12750
|
if (fullpath.length === 0) {
|
|
12259
12751
|
result.errors.push(mapper(issue2));
|
|
12260
12752
|
continue;
|
|
@@ -12286,8 +12778,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
12286
12778
|
}
|
|
12287
12779
|
function toDotPath(_path) {
|
|
12288
12780
|
const segs = [];
|
|
12289
|
-
const
|
|
12290
|
-
for (const seg of
|
|
12781
|
+
const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
12782
|
+
for (const seg of path13) {
|
|
12291
12783
|
if (typeof seg === "number")
|
|
12292
12784
|
segs.push(`[${seg}]`);
|
|
12293
12785
|
else if (typeof seg === "symbol")
|
|
@@ -24264,13 +24756,13 @@ function resolveRef(ref, ctx) {
|
|
|
24264
24756
|
if (!ref.startsWith("#")) {
|
|
24265
24757
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
24266
24758
|
}
|
|
24267
|
-
const
|
|
24268
|
-
if (
|
|
24759
|
+
const path13 = ref.slice(1).split("/").filter(Boolean);
|
|
24760
|
+
if (path13.length === 0) {
|
|
24269
24761
|
return ctx.rootSchema;
|
|
24270
24762
|
}
|
|
24271
24763
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
24272
|
-
if (
|
|
24273
|
-
const key =
|
|
24764
|
+
if (path13[0] === defsKey) {
|
|
24765
|
+
const key = path13[1];
|
|
24274
24766
|
if (!key || !ctx.defs[key]) {
|
|
24275
24767
|
throw new Error(`Reference not found: ${ref}`);
|
|
24276
24768
|
}
|
|
@@ -28195,10 +28687,10 @@ function parseQoderSkillsList(output, cwd, home = os4.homedir()) {
|
|
|
28195
28687
|
finish();
|
|
28196
28688
|
return skills;
|
|
28197
28689
|
}
|
|
28198
|
-
function qoderManagedExecutableCandidates(home) {
|
|
28690
|
+
function qoderManagedExecutableCandidates(home, readdirSync2 = fs7.readdirSync) {
|
|
28199
28691
|
const directory = path8.join(home, ".qoder", "bin", "qodercli");
|
|
28200
28692
|
try {
|
|
28201
|
-
return
|
|
28693
|
+
return readdirSync2(directory, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.startsWith("qodercli-")).sort((left, right) => right.name.localeCompare(left.name, void 0, { numeric: true })).map((entry) => path8.join(directory, entry.name));
|
|
28202
28694
|
} catch {
|
|
28203
28695
|
return [];
|
|
28204
28696
|
}
|
|
@@ -28213,6 +28705,25 @@ function isPermissionResponse(value) {
|
|
|
28213
28705
|
function qoderInstallCommand(platform = process.platform) {
|
|
28214
28706
|
return platform === "win32" ? "npm install -g @qoder-ai/qodercli" : "curl -fsSL https://qoder.com/install | bash";
|
|
28215
28707
|
}
|
|
28708
|
+
function qoderExecutableCandidatePaths(options = {}) {
|
|
28709
|
+
const env = options.env ?? process.env;
|
|
28710
|
+
const home = (options.homedir ?? os4.homedir)();
|
|
28711
|
+
const platform = options.platform ?? process.platform;
|
|
28712
|
+
const executableNames2 = platform === "win32" ? ["qodercli.exe", "qodercli.cmd"] : ["qodercli"];
|
|
28713
|
+
return agentExecutableCandidatePaths({
|
|
28714
|
+
executableNames: executableNames2,
|
|
28715
|
+
configuredPath: env.MEARL_QODER_PATH,
|
|
28716
|
+
env,
|
|
28717
|
+
extraUserCandidates: [
|
|
28718
|
+
...qoderManagedExecutableCandidates(home, options.readdirSync),
|
|
28719
|
+
...executableNames2.map((name) => path8.join(home, ".qoder", "bin", name))
|
|
28720
|
+
],
|
|
28721
|
+
home,
|
|
28722
|
+
platform,
|
|
28723
|
+
processExecPath: options.processExecPath,
|
|
28724
|
+
readdirSync: options.readdirSync
|
|
28725
|
+
});
|
|
28726
|
+
}
|
|
28216
28727
|
function sessionOptions(options) {
|
|
28217
28728
|
const cwd = path8.resolve(options.cwd || os4.homedir());
|
|
28218
28729
|
return {
|
|
@@ -28618,11 +29129,11 @@ ${message}` : message;
|
|
|
28618
29129
|
throw new Error(resolution.error);
|
|
28619
29130
|
}
|
|
28620
29131
|
const { executable } = resolution;
|
|
28621
|
-
const launch =
|
|
28622
|
-
const child =
|
|
29132
|
+
const launch = resolveSpawnCommand(executable, ["--acp"]);
|
|
29133
|
+
const child = spawn7(launch.command, launch.args, {
|
|
28623
29134
|
stdio: ["pipe", "pipe", "pipe"],
|
|
28624
29135
|
windowsHide: true,
|
|
28625
|
-
env:
|
|
29136
|
+
env: prependNodePath()
|
|
28626
29137
|
});
|
|
28627
29138
|
this.process = child;
|
|
28628
29139
|
child.stderr.on("data", (chunk) => {
|
|
@@ -28965,12 +29476,12 @@ ${message}` : message;
|
|
|
28965
29476
|
}
|
|
28966
29477
|
runSkillsList(executable, cwd) {
|
|
28967
29478
|
return new Promise((resolve, reject) => {
|
|
28968
|
-
const launch =
|
|
28969
|
-
const child =
|
|
29479
|
+
const launch = resolveSpawnCommand(executable, ["skill", "list", "--all"]);
|
|
29480
|
+
const child = spawn7(launch.command, launch.args, {
|
|
28970
29481
|
cwd,
|
|
28971
29482
|
stdio: ["ignore", "pipe", "pipe"],
|
|
28972
29483
|
windowsHide: true,
|
|
28973
|
-
env:
|
|
29484
|
+
env: prependNodePath()
|
|
28974
29485
|
});
|
|
28975
29486
|
let stdout = "";
|
|
28976
29487
|
let stderr = "";
|
|
@@ -29004,89 +29515,60 @@ ${message}` : message;
|
|
|
29004
29515
|
return this.executableResolver.resolve();
|
|
29005
29516
|
}
|
|
29006
29517
|
resolveExecutableCandidates() {
|
|
29007
|
-
|
|
29008
|
-
const configured = process.env.MEARL_QODER_PATH;
|
|
29009
|
-
const home = os4.homedir();
|
|
29010
|
-
const pathCandidates = (process.env.PATH || "").split(path8.delimiter).filter(Boolean).flatMap((dir) => executableNames.map((name) => path8.join(dir, name)));
|
|
29011
|
-
return executableFileCandidates([
|
|
29012
|
-
configured,
|
|
29013
|
-
...executableNames.map((name) => path8.join(path8.dirname(process.execPath), name)),
|
|
29014
|
-
...executableNames.map((name) => path8.join(home, ".local", "bin", name)),
|
|
29015
|
-
...qoderManagedExecutableCandidates(home),
|
|
29016
|
-
...executableNames.map((name) => path8.join(home, ".qoder", "bin", name)),
|
|
29017
|
-
...process.platform === "win32" ? [] : ["/opt/homebrew/bin/qodercli", "/usr/local/bin/qodercli", "/usr/bin/qodercli"],
|
|
29018
|
-
...pathCandidates
|
|
29019
|
-
]);
|
|
29518
|
+
return executableFileCandidates(qoderExecutableCandidatePaths());
|
|
29020
29519
|
}
|
|
29021
29520
|
emit(event) {
|
|
29022
29521
|
for (const listener of this.listeners) listener(event);
|
|
29023
29522
|
}
|
|
29024
29523
|
};
|
|
29025
29524
|
|
|
29026
|
-
//
|
|
29027
|
-
import
|
|
29525
|
+
// ../setup/dist/aliSkills.js
|
|
29526
|
+
import fs8 from "node:fs";
|
|
29028
29527
|
import os5 from "node:os";
|
|
29029
29528
|
import path9 from "node:path";
|
|
29030
|
-
import { spawn as
|
|
29529
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
29031
29530
|
var COMMAND_TIMEOUT_MS = 12e4;
|
|
29032
29531
|
var MAX_OUTPUT_LENGTH = 1e6;
|
|
29033
29532
|
var ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\u001B\[[0-?]*[ -/]*[@-~]`, "g");
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
for (const candidate of candidates) {
|
|
29037
|
-
if (!candidate) continue;
|
|
29038
|
-
try {
|
|
29039
|
-
fs7.accessSync(
|
|
29040
|
-
candidate,
|
|
29041
|
-
process.platform === "win32" ? fs7.constants.F_OK : fs7.constants.X_OK
|
|
29042
|
-
);
|
|
29043
|
-
return candidate;
|
|
29044
|
-
} catch {
|
|
29045
|
-
}
|
|
29046
|
-
}
|
|
29047
|
-
return null;
|
|
29533
|
+
function existingExecutable(candidates, existsSync4) {
|
|
29534
|
+
return candidates.find((candidate) => candidate && existsSync4(candidate)) ?? null;
|
|
29048
29535
|
}
|
|
29049
|
-
function
|
|
29050
|
-
|
|
29051
|
-
path9.join(home, ".nvm", "versions", "node"),
|
|
29052
|
-
path9.join(home, ".fnm", "node-versions")
|
|
29053
|
-
];
|
|
29054
|
-
return roots.flatMap((root) => {
|
|
29055
|
-
try {
|
|
29056
|
-
return fs7.readdirSync(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((left, right) => right.name.localeCompare(left.name, void 0, { numeric: true })).flatMap(
|
|
29057
|
-
(entry) => executableNames.flatMap((name) => [
|
|
29058
|
-
path9.join(root, entry.name, "bin", name),
|
|
29059
|
-
path9.join(root, entry.name, "installation", "bin", name)
|
|
29060
|
-
])
|
|
29061
|
-
);
|
|
29062
|
-
} catch {
|
|
29063
|
-
return [];
|
|
29064
|
-
}
|
|
29065
|
-
});
|
|
29536
|
+
function stripAnsi(value) {
|
|
29537
|
+
return value.replace(ANSI_ESCAPE_PATTERN, "");
|
|
29066
29538
|
}
|
|
29067
|
-
function resolveAliSkillsExecutable() {
|
|
29068
|
-
const
|
|
29069
|
-
const home = os5.homedir();
|
|
29070
|
-
const
|
|
29539
|
+
function resolveAliSkillsExecutable(options = {}) {
|
|
29540
|
+
const env = options.env ?? process.env;
|
|
29541
|
+
const home = (options.homedir ?? os5.homedir)();
|
|
29542
|
+
const platform = options.platform ?? process.platform;
|
|
29543
|
+
const existsSync4 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
|
|
29544
|
+
const processExecPath = options.processExecPath ?? process.execPath;
|
|
29545
|
+
const readdirSync2 = options.readdirSync ?? fs8.readdirSync;
|
|
29546
|
+
const names = executableNames("ali-skills", platform);
|
|
29547
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
29548
|
+
const pathCandidates = (env[pathKey] || "").split(path9.delimiter).filter(Boolean).flatMap((directory) => names.map((name) => path9.join(directory, name)));
|
|
29071
29549
|
const candidates = [
|
|
29072
|
-
|
|
29073
|
-
...
|
|
29074
|
-
...
|
|
29075
|
-
...
|
|
29076
|
-
...
|
|
29077
|
-
...
|
|
29078
|
-
...
|
|
29079
|
-
...
|
|
29080
|
-
|
|
29550
|
+
env.MEARL_ALI_SKILLS_PATH,
|
|
29551
|
+
...names.map((name) => path9.join(path9.dirname(processExecPath), name)),
|
|
29552
|
+
...names.map((name) => path9.join(home, ".local", "bin", name)),
|
|
29553
|
+
...names.map((name) => path9.join(home, ".npm-global", "bin", name)),
|
|
29554
|
+
...names.map((name) => path9.join(home, ".volta", "bin", name)),
|
|
29555
|
+
...names.map((name) => path9.join(home, ".local", "share", "pnpm", name)),
|
|
29556
|
+
...names.map((name) => path9.join(home, "Library", "pnpm", name)),
|
|
29557
|
+
...versionManagerExecutableCandidates(home, names, {
|
|
29558
|
+
env,
|
|
29559
|
+
platform,
|
|
29560
|
+
readdirSync: readdirSync2
|
|
29561
|
+
}),
|
|
29562
|
+
...platform === "win32" ? [] : ["/opt/homebrew/bin/ali-skills", "/usr/local/bin/ali-skills", "/usr/bin/ali-skills"],
|
|
29081
29563
|
...pathCandidates
|
|
29082
29564
|
];
|
|
29083
|
-
return existingExecutable(candidates);
|
|
29565
|
+
return existingExecutable(candidates, existsSync4);
|
|
29084
29566
|
}
|
|
29085
|
-
var
|
|
29086
|
-
const launch =
|
|
29087
|
-
const child =
|
|
29567
|
+
var runAliSkillsCli = (executable, args, cwd) => new Promise((resolve, reject) => {
|
|
29568
|
+
const launch = resolveSpawnCommand(executable, args);
|
|
29569
|
+
const child = spawn8(launch.command, launch.args, {
|
|
29088
29570
|
cwd,
|
|
29089
|
-
env:
|
|
29571
|
+
env: prependNodePath(prependCommandPath(executable)),
|
|
29090
29572
|
stdio: ["ignore", "pipe", "pipe"],
|
|
29091
29573
|
windowsHide: true
|
|
29092
29574
|
});
|
|
@@ -29095,11 +29577,14 @@ var runSkillCli = (executable, args, cwd) => new Promise((resolve, reject) => {
|
|
|
29095
29577
|
let settled = false;
|
|
29096
29578
|
const append = (current, chunk) => current.length >= MAX_OUTPUT_LENGTH ? current : (current + chunk.toString("utf8")).slice(0, MAX_OUTPUT_LENGTH);
|
|
29097
29579
|
const finish = (error48) => {
|
|
29098
|
-
if (settled)
|
|
29580
|
+
if (settled)
|
|
29581
|
+
return;
|
|
29099
29582
|
settled = true;
|
|
29100
29583
|
clearTimeout(timer);
|
|
29101
|
-
if (error48)
|
|
29102
|
-
|
|
29584
|
+
if (error48)
|
|
29585
|
+
reject(error48);
|
|
29586
|
+
else
|
|
29587
|
+
resolve({ stdout, stderr });
|
|
29103
29588
|
};
|
|
29104
29589
|
const timer = setTimeout(() => {
|
|
29105
29590
|
child.kill("SIGTERM");
|
|
@@ -29117,9 +29602,10 @@ var runSkillCli = (executable, args, cwd) => new Promise((resolve, reject) => {
|
|
|
29117
29602
|
finish(new Error(detail || `Ali Skills command exited with code ${String(code)}`));
|
|
29118
29603
|
});
|
|
29119
29604
|
});
|
|
29120
|
-
|
|
29121
|
-
|
|
29122
|
-
|
|
29605
|
+
|
|
29606
|
+
// src/agent/skill-manager.ts
|
|
29607
|
+
var SETUP_COMMAND = "npm install -g ali-skills";
|
|
29608
|
+
var runSkillCli = runAliSkillsCli;
|
|
29123
29609
|
function validateProvider(value) {
|
|
29124
29610
|
if (value !== "codex" && value !== "qoder") {
|
|
29125
29611
|
throw new Error("Skill provider must be codex or qoder");
|
|
@@ -29304,7 +29790,7 @@ var CDP_PORT = positivePort(cliOption("--cdp-port"), 9222);
|
|
|
29304
29790
|
var CDP_USER_DATA_DIR = cliOption("--cdp-user-data-dir");
|
|
29305
29791
|
var CDP_BROWSER_ID = cliOption("--browser-id") ?? "cdp";
|
|
29306
29792
|
var CDP_BROWSER_NAME = cliOption("--browser-name") ?? "CDP";
|
|
29307
|
-
if (cliArg === "--init") {
|
|
29793
|
+
if (cliArg === "--init" || cliArg === "--uninstall") {
|
|
29308
29794
|
const { runCli: runCli2 } = await Promise.resolve().then(() => (init_install(), install_exports));
|
|
29309
29795
|
await runCli2(process.argv.slice(2));
|
|
29310
29796
|
process.exit(0);
|
|
@@ -29323,6 +29809,8 @@ Options:
|
|
|
29323
29809
|
--init [--mode <skills|mcp|both>] [--extension-id <id>]
|
|
29324
29810
|
Initialize Native Messaging Host
|
|
29325
29811
|
(default: both — installs the Skills and MCP hosts)
|
|
29812
|
+
--uninstall [--mode <skills|mcp|both>]
|
|
29813
|
+
Remove Native Messaging Host registration
|
|
29326
29814
|
--daemon Start as standalone CDP daemon (no extension needed)
|
|
29327
29815
|
--cdp-port <port> CDP port for daemon mode (default 9222)
|
|
29328
29816
|
--cdp-user-data-dir <dir> Read DevToolsActivePort from this Chrome profile
|
|
@@ -29340,17 +29828,18 @@ Connection modes (auto-detected at runtime):
|
|
|
29340
29828
|
Examples:
|
|
29341
29829
|
mearl-native-host --init
|
|
29342
29830
|
mearl-native-host --init --mode skills
|
|
29831
|
+
mearl-native-host --uninstall --mode skills
|
|
29343
29832
|
mearl-native-host --init --extension-id abcdefghijklmnopqrstuvwxyzabcdef
|
|
29344
29833
|
mearl-native-host --daemon
|
|
29345
29834
|
mearl-native-host --version`);
|
|
29346
29835
|
process.exit(0);
|
|
29347
29836
|
}
|
|
29348
29837
|
function socketPathFor(suffix) {
|
|
29349
|
-
return process.platform === "win32" ? `\\\\.\\pipe\\mearl-agent${suffix}` :
|
|
29838
|
+
return process.platform === "win32" ? `\\\\.\\pipe\\mearl-agent${suffix}` : path12.join(os7.tmpdir(), `mearl-agent${suffix}.sock`);
|
|
29350
29839
|
}
|
|
29351
29840
|
var LEGACY_SOCKET_PATH = socketPathFor("");
|
|
29352
29841
|
var INSTANCE_SOCKET_PATH = socketPathFor(`-${process.pid}`);
|
|
29353
|
-
var LOG_FILE =
|
|
29842
|
+
var LOG_FILE = path12.join(os7.tmpdir(), "mearl-native-host.log");
|
|
29354
29843
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
29355
29844
|
var INVENTORY_IDLE_EXIT_MS = 1e3;
|
|
29356
29845
|
var MAX_SOCKET_BUFFER_SIZE = 64 * 1024 * 1024;
|
|
@@ -29449,7 +29938,7 @@ function log(...args) {
|
|
|
29449
29938
|
const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [NativeHost] ${args.join(" ")}
|
|
29450
29939
|
`;
|
|
29451
29940
|
try {
|
|
29452
|
-
|
|
29941
|
+
fs11.appendFileSync(LOG_FILE, msg);
|
|
29453
29942
|
} catch {
|
|
29454
29943
|
}
|
|
29455
29944
|
}
|
|
@@ -29983,7 +30472,7 @@ function onSocketConnection(socket) {
|
|
|
29983
30472
|
}
|
|
29984
30473
|
function isPathAlive(socketPath) {
|
|
29985
30474
|
return new Promise((resolve) => {
|
|
29986
|
-
if (process.platform !== "win32" && !
|
|
30475
|
+
if (process.platform !== "win32" && !fs11.existsSync(socketPath)) {
|
|
29987
30476
|
resolve(false);
|
|
29988
30477
|
return;
|
|
29989
30478
|
}
|
|
@@ -30006,9 +30495,9 @@ function isPathAlive(socketPath) {
|
|
|
30006
30495
|
}
|
|
30007
30496
|
function listenOn(socketPath) {
|
|
30008
30497
|
return new Promise((resolve, reject) => {
|
|
30009
|
-
if (process.platform !== "win32" &&
|
|
30498
|
+
if (process.platform !== "win32" && fs11.existsSync(socketPath)) {
|
|
30010
30499
|
try {
|
|
30011
|
-
|
|
30500
|
+
fs11.unlinkSync(socketPath);
|
|
30012
30501
|
} catch {
|
|
30013
30502
|
}
|
|
30014
30503
|
}
|
|
@@ -30017,11 +30506,11 @@ function listenOn(socketPath) {
|
|
|
30017
30506
|
server.listen(socketPath, () => {
|
|
30018
30507
|
if (process.platform !== "win32") {
|
|
30019
30508
|
try {
|
|
30020
|
-
|
|
30509
|
+
fs11.chmodSync(socketPath, 384);
|
|
30021
30510
|
} catch (error48) {
|
|
30022
30511
|
server.close();
|
|
30023
30512
|
try {
|
|
30024
|
-
|
|
30513
|
+
fs11.unlinkSync(socketPath);
|
|
30025
30514
|
} catch {
|
|
30026
30515
|
}
|
|
30027
30516
|
reject(error48);
|
|
@@ -30057,7 +30546,7 @@ function releaseLegacySocket() {
|
|
|
30057
30546
|
}
|
|
30058
30547
|
if (process.platform !== "win32") {
|
|
30059
30548
|
try {
|
|
30060
|
-
if (
|
|
30549
|
+
if (fs11.existsSync(LEGACY_SOCKET_PATH)) fs11.unlinkSync(LEGACY_SOCKET_PATH);
|
|
30061
30550
|
} catch {
|
|
30062
30551
|
}
|
|
30063
30552
|
}
|
|
@@ -30069,8 +30558,8 @@ async function startSocketServer() {
|
|
|
30069
30558
|
function cleanupInstanceSocketFile() {
|
|
30070
30559
|
if (process.platform === "win32") return;
|
|
30071
30560
|
try {
|
|
30072
|
-
if (
|
|
30073
|
-
|
|
30561
|
+
if (fs11.existsSync(INSTANCE_SOCKET_PATH)) {
|
|
30562
|
+
fs11.unlinkSync(INSTANCE_SOCKET_PATH);
|
|
30074
30563
|
}
|
|
30075
30564
|
} catch (error48) {
|
|
30076
30565
|
log("cleanup socket file failed:", String(error48));
|