@mearl/native-host 2.2.2 → 2.4.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 +1 -1
- package/dist/agent/qoder-provider.d.ts +10 -0
- 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/host-updater.d.ts +39 -0
- package/dist/index.js +1177 -327
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -10,20 +10,20 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// ../setup/dist/nativeHost.js
|
|
13
|
-
import
|
|
13
|
+
import fs11 from "node:fs";
|
|
14
14
|
import os6 from "node:os";
|
|
15
|
-
import
|
|
15
|
+
import path12 from "node:path";
|
|
16
16
|
import { execFileSync } from "node:child_process";
|
|
17
17
|
function resolveNativeHostDirectory(options = {}) {
|
|
18
18
|
const env = options.env ?? process.env;
|
|
19
19
|
const home = (options.homedir ?? os6.homedir)();
|
|
20
20
|
switch (options.platform ?? process.platform) {
|
|
21
21
|
case "darwin":
|
|
22
|
-
return
|
|
22
|
+
return path12.join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts");
|
|
23
23
|
case "linux":
|
|
24
|
-
return
|
|
24
|
+
return path12.join(home, ".config/google-chrome/NativeMessagingHosts");
|
|
25
25
|
case "win32":
|
|
26
|
-
return
|
|
26
|
+
return path12.join(env.PROGRAMDATA || "C:\\ProgramData", "Google\\Chrome\\NativeMessagingHosts");
|
|
27
27
|
default:
|
|
28
28
|
throw new Error(`Unsupported platform: ${String(options.platform ?? process.platform)}`);
|
|
29
29
|
}
|
|
@@ -46,20 +46,20 @@ function uninstallNativeHostArtifacts(options = {}, dependencies = {}) {
|
|
|
46
46
|
writeLine(line);
|
|
47
47
|
};
|
|
48
48
|
try {
|
|
49
|
-
const existsSync4 = dependencies.existsSync ??
|
|
49
|
+
const existsSync4 = dependencies.existsSync ?? fs11.existsSync;
|
|
50
50
|
const platform = dependencies.platform ?? process.platform;
|
|
51
51
|
const hostDir = dependencies.hostDir ?? resolveNativeHostDirectory({
|
|
52
52
|
env: dependencies.env,
|
|
53
53
|
homedir: dependencies.homedir,
|
|
54
54
|
platform
|
|
55
55
|
});
|
|
56
|
-
const unlinkSync = dependencies.unlinkSync ??
|
|
56
|
+
const unlinkSync = dependencies.unlinkSync ?? fs11.unlinkSync;
|
|
57
57
|
const unregister = dependencies.unregisterWindowsNativeHost ?? unregisterWindowsNativeHost;
|
|
58
58
|
const hostName = MEARL_NATIVE_HOST_NAMES[mode];
|
|
59
59
|
const launcherExtension = platform === "win32" ? "cmd" : "sh";
|
|
60
60
|
const artifacts = [
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
path12.join(hostDir, `${hostName}.json`),
|
|
62
|
+
path12.join(hostDir, `${hostName}-launcher.${launcherExtension}`)
|
|
63
63
|
];
|
|
64
64
|
for (const artifact of artifacts) {
|
|
65
65
|
if (!existsSync4(artifact))
|
|
@@ -94,17 +94,17 @@ __export(install_exports, {
|
|
|
94
94
|
runCli: () => runCli,
|
|
95
95
|
uninstallNativeHost: () => uninstallNativeHost
|
|
96
96
|
});
|
|
97
|
-
import
|
|
98
|
-
import
|
|
97
|
+
import fs12 from "node:fs";
|
|
98
|
+
import path13 from "node:path";
|
|
99
99
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
100
100
|
import { createRequire } from "node:module";
|
|
101
|
-
import { fileURLToPath } from "node:url";
|
|
101
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
102
102
|
function resolveHostDir() {
|
|
103
103
|
return resolveNativeHostDirectory();
|
|
104
104
|
}
|
|
105
105
|
function resolveNativeHostPath() {
|
|
106
|
-
const siblingPath =
|
|
107
|
-
if (
|
|
106
|
+
const siblingPath = path13.join(__dirname, "index.js");
|
|
107
|
+
if (fs12.existsSync(siblingPath)) {
|
|
108
108
|
return siblingPath;
|
|
109
109
|
}
|
|
110
110
|
try {
|
|
@@ -123,16 +123,16 @@ function registerWindowsNativeHost(hostName, manifestPath) {
|
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
125
|
function createLauncherScript(hostDir, hostPath, hostName) {
|
|
126
|
-
const nodePath =
|
|
126
|
+
const nodePath = path13.resolve(process.execPath);
|
|
127
127
|
if (process.platform === "win32") {
|
|
128
|
-
const launcherPath2 =
|
|
128
|
+
const launcherPath2 = path13.join(hostDir, `${hostName}-launcher.cmd`);
|
|
129
129
|
const content2 = `@echo off\r
|
|
130
130
|
"${nodePath}" "${hostPath}" %*\r
|
|
131
131
|
`;
|
|
132
|
-
|
|
132
|
+
fs12.writeFileSync(launcherPath2, content2, "utf-8");
|
|
133
133
|
return launcherPath2;
|
|
134
134
|
}
|
|
135
|
-
const launcherPath =
|
|
135
|
+
const launcherPath = path13.join(hostDir, `${hostName}-launcher.sh`);
|
|
136
136
|
const content = [
|
|
137
137
|
"#!/bin/sh",
|
|
138
138
|
`NODE_BIN=${JSON.stringify(nodePath)}`,
|
|
@@ -140,8 +140,8 @@ function createLauncherScript(hostDir, hostPath, hostName) {
|
|
|
140
140
|
'exec "$NODE_BIN" "$HOST_SCRIPT" "$@"',
|
|
141
141
|
""
|
|
142
142
|
].join("\n");
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
fs12.writeFileSync(launcherPath, content, "utf-8");
|
|
144
|
+
fs12.chmodSync(launcherPath, 493);
|
|
145
145
|
return launcherPath;
|
|
146
146
|
}
|
|
147
147
|
async function installNativeHost(options = {}) {
|
|
@@ -167,14 +167,14 @@ async function installNativeHost(options = {}) {
|
|
|
167
167
|
try {
|
|
168
168
|
const hostDir = resolveHostDir();
|
|
169
169
|
if (skipIfExists) {
|
|
170
|
-
const manifestPath2 =
|
|
171
|
-
if (
|
|
170
|
+
const manifestPath2 = path13.join(hostDir, `${hostName}.json`);
|
|
171
|
+
if (fs12.existsSync(manifestPath2)) {
|
|
172
172
|
log2(`✅ Already installed: ${manifestPath2}`);
|
|
173
173
|
return true;
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
-
if (!
|
|
177
|
-
|
|
176
|
+
if (!fs12.existsSync(hostDir)) {
|
|
177
|
+
fs12.mkdirSync(hostDir, { recursive: true });
|
|
178
178
|
log2(`✅ Created directory: ${hostDir}`);
|
|
179
179
|
}
|
|
180
180
|
const resolvedHostPath = resolveNativeHostPath();
|
|
@@ -188,13 +188,13 @@ async function installNativeHost(options = {}) {
|
|
|
188
188
|
type: "stdio",
|
|
189
189
|
allowed_origins: [`chrome-extension://${extensionId}/`]
|
|
190
190
|
};
|
|
191
|
-
const manifestPath =
|
|
192
|
-
|
|
191
|
+
const manifestPath = path13.join(hostDir, `${hostName}.json`);
|
|
192
|
+
fs12.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
193
193
|
if (process.platform === "win32") {
|
|
194
194
|
registerWindowsNativeHost(hostName, manifestPath);
|
|
195
195
|
log2(`✅ Windows registry key created for: ${hostName}`);
|
|
196
196
|
} else {
|
|
197
|
-
|
|
197
|
+
fs12.chmodSync(manifestPath, 420);
|
|
198
198
|
}
|
|
199
199
|
log2(`✅ Manifest installed: ${manifestPath}`);
|
|
200
200
|
log2(`✅ Extension ID: ${extensionId}`);
|
|
@@ -306,26 +306,26 @@ var init_install = __esm({
|
|
|
306
306
|
"use strict";
|
|
307
307
|
init_nativeHost();
|
|
308
308
|
DEFAULT_EXTENSION_ID = "aoehhjnofngknnjefamjbplchbolghkm";
|
|
309
|
-
__filename =
|
|
310
|
-
__dirname =
|
|
309
|
+
__filename = fileURLToPath2(import.meta.url);
|
|
310
|
+
__dirname = path13.dirname(__filename);
|
|
311
311
|
ALL_MODES = ["skills", "mcp"];
|
|
312
312
|
}
|
|
313
313
|
});
|
|
314
314
|
|
|
315
315
|
// src/index.ts
|
|
316
316
|
import net from "node:net";
|
|
317
|
-
import
|
|
317
|
+
import fs13 from "node:fs";
|
|
318
318
|
import http5 from "node:http";
|
|
319
319
|
import os7 from "node:os";
|
|
320
|
-
import
|
|
321
|
-
import { fileURLToPath as
|
|
320
|
+
import path14 from "node:path";
|
|
321
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
322
322
|
|
|
323
323
|
// src/cdp-backend/cdp-session.ts
|
|
324
324
|
import http3 from "node:http";
|
|
325
325
|
|
|
326
326
|
// src/cdp-backend/client.ts
|
|
327
327
|
import http from "node:http";
|
|
328
|
-
import
|
|
328
|
+
import crypto2 from "node:crypto";
|
|
329
329
|
var CdpChildSession = class {
|
|
330
330
|
constructor(parent, sessionId) {
|
|
331
331
|
this.parent = parent;
|
|
@@ -406,8 +406,8 @@ var CdpClient = class _CdpClient {
|
|
|
406
406
|
return new Promise((resolve, reject) => {
|
|
407
407
|
const url2 = new URL(wsUrl);
|
|
408
408
|
const port = parseInt(url2.port || "9222", 10);
|
|
409
|
-
const key =
|
|
410
|
-
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");
|
|
411
411
|
const req = http.request({
|
|
412
412
|
host: url2.hostname,
|
|
413
413
|
port,
|
|
@@ -559,7 +559,7 @@ var CdpClient = class _CdpClient {
|
|
|
559
559
|
sendText(text) {
|
|
560
560
|
if (this._closed) return;
|
|
561
561
|
const payload = Buffer.from(text, "utf-8");
|
|
562
|
-
const maskKey =
|
|
562
|
+
const maskKey = crypto2.randomBytes(4);
|
|
563
563
|
const masked = Buffer.from(payload.map((b, i) => b ^ maskKey[i % 4]));
|
|
564
564
|
let header;
|
|
565
565
|
if (payload.length < 126) {
|
|
@@ -754,6 +754,9 @@ function buildCookieHeaderValue(cookieMap) {
|
|
|
754
754
|
var APLUS_URL_PATTERN = /\.mmstat\.com\//;
|
|
755
755
|
var RUM_URL_PATTERN = /\.rum\.aliyuncs\.com\//;
|
|
756
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
|
+
}
|
|
757
760
|
var aplusCounter = 0;
|
|
758
761
|
var armsCounter = 0;
|
|
759
762
|
var rumCounter = 0;
|
|
@@ -1163,13 +1166,13 @@ function queryTrackingEvents(buffer, options = {}) {
|
|
|
1163
1166
|
}
|
|
1164
1167
|
|
|
1165
1168
|
// ../browser-core/dist/requestSerializer.js
|
|
1166
|
-
function parsePath(
|
|
1167
|
-
if (
|
|
1169
|
+
function parsePath(path15) {
|
|
1170
|
+
if (path15.length > 1e3)
|
|
1168
1171
|
throw new Error("Path too long: maximum 1000 characters allowed");
|
|
1169
1172
|
const keys = [];
|
|
1170
1173
|
let current = "";
|
|
1171
|
-
for (let i = 0; i <
|
|
1172
|
-
const char =
|
|
1174
|
+
for (let i = 0; i < path15.length; i++) {
|
|
1175
|
+
const char = path15[i];
|
|
1173
1176
|
if (char === ".") {
|
|
1174
1177
|
if (current) {
|
|
1175
1178
|
keys.push(current);
|
|
@@ -1181,10 +1184,10 @@ function parsePath(path13) {
|
|
|
1181
1184
|
current = "";
|
|
1182
1185
|
}
|
|
1183
1186
|
let j = i + 1;
|
|
1184
|
-
while (j <
|
|
1187
|
+
while (j < path15.length && path15[j] !== "]")
|
|
1185
1188
|
j++;
|
|
1186
|
-
if (j <
|
|
1187
|
-
const index = parseInt(
|
|
1189
|
+
if (j < path15.length) {
|
|
1190
|
+
const index = parseInt(path15.substring(i + 1, j), 10);
|
|
1188
1191
|
if (!isNaN(index)) {
|
|
1189
1192
|
if (index < 0 || index > 1e5)
|
|
1190
1193
|
throw new Error(`Array index out of safe range: ${index}`);
|
|
@@ -1202,8 +1205,8 @@ function parsePath(path13) {
|
|
|
1202
1205
|
throw new Error("Path too deep: maximum 50 levels allowed");
|
|
1203
1206
|
return keys;
|
|
1204
1207
|
}
|
|
1205
|
-
function getValueByPath(obj,
|
|
1206
|
-
const keys = parsePath(
|
|
1208
|
+
function getValueByPath(obj, path15) {
|
|
1209
|
+
const keys = parsePath(path15);
|
|
1207
1210
|
let current = obj;
|
|
1208
1211
|
for (const key of keys) {
|
|
1209
1212
|
if (current === null || current === void 0)
|
|
@@ -1212,8 +1215,8 @@ function getValueByPath(obj, path13) {
|
|
|
1212
1215
|
}
|
|
1213
1216
|
return current;
|
|
1214
1217
|
}
|
|
1215
|
-
function setValueByPath(obj,
|
|
1216
|
-
const keys = parsePath(
|
|
1218
|
+
function setValueByPath(obj, path15, value) {
|
|
1219
|
+
const keys = parsePath(path15);
|
|
1217
1220
|
let current = obj;
|
|
1218
1221
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
1219
1222
|
const key = keys[i];
|
|
@@ -1287,7 +1290,11 @@ function serializeRequest(request, options = {}) {
|
|
|
1287
1290
|
status: request.status,
|
|
1288
1291
|
statusText: request.statusText,
|
|
1289
1292
|
queryString: request.queryString,
|
|
1290
|
-
duration: request.duration
|
|
1293
|
+
duration: request.duration,
|
|
1294
|
+
captureSequence: request.captureSequence,
|
|
1295
|
+
isPending: request.isPending,
|
|
1296
|
+
source: request.source,
|
|
1297
|
+
resourceType: request.resourceType
|
|
1291
1298
|
};
|
|
1292
1299
|
if (includeHeaders) {
|
|
1293
1300
|
result.headers = request.headers;
|
|
@@ -1411,10 +1418,14 @@ function applyFieldLimits(request, maxFieldBytes) {
|
|
|
1411
1418
|
request.responseBody = limitBufferedField(request.responseBody, maxFieldBytes);
|
|
1412
1419
|
}
|
|
1413
1420
|
function trimRequestBuffer(requests, accounting, maxEntries, maxBytes) {
|
|
1421
|
+
const removed = [];
|
|
1414
1422
|
while (requests.length > 1 && (requests.length > maxEntries || accounting.totalBytes > maxBytes)) {
|
|
1415
|
-
requests.shift();
|
|
1423
|
+
const request = requests.shift();
|
|
1424
|
+
if (request)
|
|
1425
|
+
removed.push(request);
|
|
1416
1426
|
accounting.totalBytes -= accounting.sizes.shift() ?? 0;
|
|
1417
1427
|
}
|
|
1428
|
+
return removed;
|
|
1418
1429
|
}
|
|
1419
1430
|
function appendRequestToBuffer(requests, accounting, request, limits = {}) {
|
|
1420
1431
|
const { maxEntries = REQUEST_BUFFER_MAX_ENTRIES, maxBytes = REQUEST_BUFFER_MAX_BYTES, maxFieldBytes = REQUEST_BUFFER_MAX_FIELD_BYTES } = limits;
|
|
@@ -1424,20 +1435,20 @@ function appendRequestToBuffer(requests, accounting, request, limits = {}) {
|
|
|
1424
1435
|
requests.push(request);
|
|
1425
1436
|
accounting.sizes.push(size);
|
|
1426
1437
|
accounting.totalBytes += size;
|
|
1427
|
-
trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1438
|
+
return trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1428
1439
|
}
|
|
1429
1440
|
function refreshRequestInBuffer(requests, accounting, request, limits = {}) {
|
|
1430
1441
|
const { maxEntries = REQUEST_BUFFER_MAX_ENTRIES, maxBytes = REQUEST_BUFFER_MAX_BYTES, maxFieldBytes = REQUEST_BUFFER_MAX_FIELD_BYTES } = limits;
|
|
1431
1442
|
const index = requests.indexOf(request);
|
|
1432
1443
|
if (index === -1)
|
|
1433
|
-
return;
|
|
1444
|
+
return [];
|
|
1434
1445
|
synchronizeAccounting(requests, accounting);
|
|
1435
1446
|
applyFieldLimits(request, maxFieldBytes);
|
|
1436
1447
|
const previousSize = accounting.sizes[index] ?? 0;
|
|
1437
1448
|
const nextSize = estimateRequestBufferBytes(request);
|
|
1438
1449
|
accounting.sizes[index] = nextSize;
|
|
1439
1450
|
accounting.totalBytes += nextSize - previousSize;
|
|
1440
|
-
trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1451
|
+
return trimRequestBuffer(requests, accounting, maxEntries, maxBytes);
|
|
1441
1452
|
}
|
|
1442
1453
|
|
|
1443
1454
|
// ../browser-core/dist/proxyPermissions.js
|
|
@@ -2741,19 +2752,19 @@ function installPageObserverInPage(maxBatches = 50) {
|
|
|
2741
2752
|
}
|
|
2742
2753
|
}
|
|
2743
2754
|
}
|
|
2744
|
-
const
|
|
2755
|
+
const path15 = [];
|
|
2745
2756
|
let current = input;
|
|
2746
|
-
while (current && current !== document.documentElement &&
|
|
2757
|
+
while (current && current !== document.documentElement && path15.length < 6) {
|
|
2747
2758
|
const parent = current.parentElement;
|
|
2748
2759
|
const currentTag = current.tagName.toLowerCase();
|
|
2749
2760
|
if (!parent) {
|
|
2750
|
-
|
|
2761
|
+
path15.unshift(currentTag);
|
|
2751
2762
|
break;
|
|
2752
2763
|
}
|
|
2753
2764
|
const siblings = Array.from(parent.children).filter((item) => item.tagName === current.tagName);
|
|
2754
2765
|
const position = siblings.indexOf(current) + 1;
|
|
2755
|
-
|
|
2756
|
-
const candidate =
|
|
2766
|
+
path15.unshift(siblings.length > 1 ? `${currentTag}:nth-of-type(${position})` : currentTag);
|
|
2767
|
+
const candidate = path15.join(" > ");
|
|
2757
2768
|
if (input.isConnected) {
|
|
2758
2769
|
try {
|
|
2759
2770
|
if (document.querySelectorAll(candidate).length === 1)
|
|
@@ -2763,7 +2774,7 @@ function installPageObserverInPage(maxBatches = 50) {
|
|
|
2763
2774
|
}
|
|
2764
2775
|
current = parent;
|
|
2765
2776
|
}
|
|
2766
|
-
return
|
|
2777
|
+
return path15.join(" > ") || void 0;
|
|
2767
2778
|
};
|
|
2768
2779
|
const inferredRole = (element) => {
|
|
2769
2780
|
const explicit = element.getAttribute("role");
|
|
@@ -3470,6 +3481,7 @@ var PAGE_ACT_ACTIONS = [
|
|
|
3470
3481
|
"page_eval"
|
|
3471
3482
|
];
|
|
3472
3483
|
var BROWSER_COMMAND_ACTIONS = {
|
|
3484
|
+
capture_checkpoint: true,
|
|
3473
3485
|
get_requests: true,
|
|
3474
3486
|
get_logs: true,
|
|
3475
3487
|
get_events: true,
|
|
@@ -3512,6 +3524,7 @@ var BROWSER_COMMAND_ACTIONS = {
|
|
|
3512
3524
|
run_actions: true
|
|
3513
3525
|
};
|
|
3514
3526
|
var EXTENSION_BROWSER_ACTIONS = {
|
|
3527
|
+
capture_checkpoint: true,
|
|
3515
3528
|
get_requests: true,
|
|
3516
3529
|
get_logs: true,
|
|
3517
3530
|
get_events: true,
|
|
@@ -3558,24 +3571,35 @@ function isExtensionBrowserAction(value) {
|
|
|
3558
3571
|
}
|
|
3559
3572
|
|
|
3560
3573
|
// ../browser-core/dist/pageAct.js
|
|
3574
|
+
var DEFAULT_PAGE_DIAGNOSTICS = {
|
|
3575
|
+
logs: true,
|
|
3576
|
+
requests: true
|
|
3577
|
+
};
|
|
3561
3578
|
function isPageActAction(action) {
|
|
3562
3579
|
return PAGE_ACT_ACTIONS.includes(action);
|
|
3563
3580
|
}
|
|
3564
3581
|
function shouldObservePageAction(action, data) {
|
|
3565
3582
|
if (!isPageActAction(action))
|
|
3566
3583
|
return false;
|
|
3584
|
+
const diagnosticsEnabled = data?.diagnostics !== void 0 && data.diagnostics !== false;
|
|
3567
3585
|
if (action === "page_eval") {
|
|
3568
|
-
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));
|
|
3569
3587
|
}
|
|
3570
|
-
return data?.observe !== false;
|
|
3588
|
+
return data?.observe !== false || data?.diagnostics !== false;
|
|
3571
3589
|
}
|
|
3572
|
-
function splitObservedActionPayload(data) {
|
|
3573
|
-
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;
|
|
3574
3594
|
if (observe === false)
|
|
3575
|
-
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
|
+
}
|
|
3576
3599
|
return {
|
|
3577
3600
|
actionData,
|
|
3578
|
-
observe: observe && typeof observe === "object" && !Array.isArray(observe) ? observe : {}
|
|
3601
|
+
observe: observe && typeof observe === "object" && !Array.isArray(observe) ? observe : {},
|
|
3602
|
+
diagnostics: resolvedDiagnostics
|
|
3579
3603
|
};
|
|
3580
3604
|
}
|
|
3581
3605
|
function unavailableObservation(checkpoint, error48) {
|
|
@@ -4269,6 +4293,20 @@ function assertSendRequestBase64FileLimits(byteLengths) {
|
|
|
4269
4293
|
}
|
|
4270
4294
|
}
|
|
4271
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
|
+
|
|
4272
4310
|
// ../browser-core/dist/cookie.js
|
|
4273
4311
|
function normalizeCookieDomain(input, action) {
|
|
4274
4312
|
const value = input.trim();
|
|
@@ -4371,12 +4409,12 @@ function resolveGetCookieTarget(currentUrl, input) {
|
|
|
4371
4409
|
const url2 = parseCurrentUrl(currentUrl, action);
|
|
4372
4410
|
const name = validateCookieName(input?.name, action);
|
|
4373
4411
|
const domain2 = resolveExplicitDomain(url2, input?.domain, action);
|
|
4374
|
-
const
|
|
4412
|
+
const path15 = validateCookiePath(input?.path, action);
|
|
4375
4413
|
return {
|
|
4376
4414
|
cookieName: name,
|
|
4377
|
-
cookieUrl: `${url2.protocol}//${url2.hostname}${(
|
|
4415
|
+
cookieUrl: `${url2.protocol}//${url2.hostname}${(path15 ?? url2.pathname) || "/"}`,
|
|
4378
4416
|
...domain2 ? { domain: domain2 } : {},
|
|
4379
|
-
...
|
|
4417
|
+
...path15 ? { path: path15 } : {}
|
|
4380
4418
|
};
|
|
4381
4419
|
}
|
|
4382
4420
|
function resolveSetCookieTarget(currentUrl, input) {
|
|
@@ -4384,7 +4422,7 @@ function resolveSetCookieTarget(currentUrl, input) {
|
|
|
4384
4422
|
const url2 = parseCurrentUrl(currentUrl, action);
|
|
4385
4423
|
const name = validateCookieName(input?.name, action);
|
|
4386
4424
|
const value = validateCookieValue(input?.value);
|
|
4387
|
-
const
|
|
4425
|
+
const path15 = validateCookiePath(input?.path, action) ?? "/";
|
|
4388
4426
|
if (input.reload !== void 0 && typeof input.reload !== "boolean") {
|
|
4389
4427
|
throw new Error('set_cookie: "reload" must be a boolean');
|
|
4390
4428
|
}
|
|
@@ -4394,9 +4432,9 @@ function resolveSetCookieTarget(currentUrl, input) {
|
|
|
4394
4432
|
cookieName: name,
|
|
4395
4433
|
cookieValue: value,
|
|
4396
4434
|
...explicitDomain ? { cookieDomain: explicitDomain.includes(".") ? `.${explicitDomain}` : explicitDomain } : {},
|
|
4397
|
-
cookieUrl: `${url2.protocol}//${url2.hostname.toLowerCase()}${
|
|
4435
|
+
cookieUrl: `${url2.protocol}//${url2.hostname.toLowerCase()}${path15}`,
|
|
4398
4436
|
domain: domain2,
|
|
4399
|
-
path:
|
|
4437
|
+
path: path15,
|
|
4400
4438
|
reload: input.reload === true
|
|
4401
4439
|
};
|
|
4402
4440
|
}
|
|
@@ -4423,6 +4461,83 @@ ${SOURCE_BADGES[source]}
|
|
|
4423
4461
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
4424
4462
|
}
|
|
4425
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
|
+
|
|
4426
4541
|
// src/cdp-backend/domain-manager.ts
|
|
4427
4542
|
var enabledDomains = /* @__PURE__ */ new WeakMap();
|
|
4428
4543
|
function ensureCdpDomain(client2, domain2, params = {}) {
|
|
@@ -4444,14 +4559,22 @@ function ensureCdpDomain(client2, domain2, params = {}) {
|
|
|
4444
4559
|
// src/cdp-backend/buffers.ts
|
|
4445
4560
|
var MAX_LOGS = 500;
|
|
4446
4561
|
var MAX_EVENTS = 500;
|
|
4447
|
-
|
|
4562
|
+
var COLLECTED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["xhr", "fetch", "document"]);
|
|
4563
|
+
function createBuffers(tabId = 0) {
|
|
4448
4564
|
return {
|
|
4449
4565
|
requests: [],
|
|
4450
4566
|
logs: [],
|
|
4451
4567
|
events: [],
|
|
4452
4568
|
pending: /* @__PURE__ */ new Map(),
|
|
4453
4569
|
requestCounter: 0,
|
|
4454
|
-
requestBufferAccounting: createRequestBufferAccounting()
|
|
4570
|
+
requestBufferAccounting: createRequestBufferAccounting(),
|
|
4571
|
+
capture: {
|
|
4572
|
+
tabId,
|
|
4573
|
+
generation: createCaptureGeneration(),
|
|
4574
|
+
currentSequence: 0,
|
|
4575
|
+
droppedRequestsThroughSequence: 0,
|
|
4576
|
+
droppedLogsThroughSequence: 0
|
|
4577
|
+
}
|
|
4455
4578
|
};
|
|
4456
4579
|
}
|
|
4457
4580
|
function parseQueryString(url2) {
|
|
@@ -4467,12 +4590,34 @@ function parseQueryString(url2) {
|
|
|
4467
4590
|
function headersObjToArray(obj) {
|
|
4468
4591
|
return Object.entries(obj).map(([name, value]) => ({ name, value }));
|
|
4469
4592
|
}
|
|
4470
|
-
function
|
|
4593
|
+
function extractMtopApiName(url2, postData) {
|
|
4471
4594
|
try {
|
|
4472
4595
|
const u = new URL(url2);
|
|
4473
|
-
const
|
|
4474
|
-
if (
|
|
4475
|
-
|
|
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;
|
|
4476
4621
|
} catch {
|
|
4477
4622
|
return url2;
|
|
4478
4623
|
}
|
|
@@ -4503,28 +4648,73 @@ function appendTrackingEvents(buffers, url2, postData, sequence) {
|
|
|
4503
4648
|
}
|
|
4504
4649
|
return true;
|
|
4505
4650
|
}
|
|
4506
|
-
function
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
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) {
|
|
4516
4681
|
client2.on("Network.requestWillBeSent", (params) => {
|
|
4517
4682
|
const url2 = params.request?.url ?? "";
|
|
4518
|
-
|
|
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
|
+
}
|
|
4519
4708
|
const id = ++buffers.requestCounter;
|
|
4709
|
+
const captureSequence = nextCaptureSequence(buffers.capture);
|
|
4520
4710
|
const partial2 = {
|
|
4521
4711
|
id,
|
|
4522
4712
|
requestId: params.requestId,
|
|
4523
|
-
timestamp: new Date(
|
|
4524
|
-
timestampMs:
|
|
4713
|
+
timestamp: new Date(timestampMs2).toISOString(),
|
|
4714
|
+
timestampMs: timestampMs2,
|
|
4525
4715
|
method: params.request?.method ?? "GET",
|
|
4526
4716
|
url: url2,
|
|
4527
|
-
apiName:
|
|
4717
|
+
apiName: mtopApiName ?? requestDisplayName(url2),
|
|
4528
4718
|
headers: headersObjToArray(params.request?.headers ?? {}),
|
|
4529
4719
|
postData: parsePostData(params.request?.postData),
|
|
4530
4720
|
queryString: parseQueryString(url2),
|
|
@@ -4535,16 +4725,14 @@ function setupBufferListeners(client2, buffers) {
|
|
|
4535
4725
|
isProxy: false,
|
|
4536
4726
|
proxyRequestUrl: null,
|
|
4537
4727
|
proxyData: null,
|
|
4538
|
-
startTs: ts
|
|
4728
|
+
startTs: ts,
|
|
4729
|
+
captureSequence,
|
|
4730
|
+
isPending: true,
|
|
4731
|
+
source: isMtop ? "mtop" : "requests",
|
|
4732
|
+
resourceType
|
|
4539
4733
|
};
|
|
4540
4734
|
buffers.pending.set(params.requestId, partial2);
|
|
4541
|
-
|
|
4542
|
-
if (!captured && params.request?.hasPostData && !params.request?.postData) {
|
|
4543
|
-
client2.sendCommand("Network.getRequestPostData", { requestId: params.requestId }, 1e4).then((result) => {
|
|
4544
|
-
appendTrackingEvents(buffers, url2, result?.postData, id);
|
|
4545
|
-
}).catch(() => {
|
|
4546
|
-
});
|
|
4547
|
-
}
|
|
4735
|
+
appendCapturedRequest(buffers, partial2);
|
|
4548
4736
|
});
|
|
4549
4737
|
client2.on("Network.responseReceived", (params) => {
|
|
4550
4738
|
const partial2 = buffers.pending.get(params.requestId);
|
|
@@ -4552,73 +4740,110 @@ function setupBufferListeners(client2, buffers) {
|
|
|
4552
4740
|
partial2.status = params.response?.status ?? 0;
|
|
4553
4741
|
partial2.statusText = params.response?.statusText ?? "";
|
|
4554
4742
|
partial2.responseHeaders = headersObjToArray(params.response?.headers ?? {});
|
|
4743
|
+
refreshCapturedRequest(buffers, partial2);
|
|
4555
4744
|
});
|
|
4556
4745
|
client2.on("Network.loadingFinished", (params) => {
|
|
4557
4746
|
const partial2 = buffers.pending.get(params.requestId);
|
|
4558
4747
|
if (!partial2) return;
|
|
4559
4748
|
buffers.pending.delete(params.requestId);
|
|
4560
|
-
const endTs = params.timestamp
|
|
4561
|
-
const duration3 = Math.round((endTs - partial2.startTs) * 1e3);
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
isPending: false
|
|
4566
|
-
};
|
|
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);
|
|
4567
4754
|
client2.sendCommand("Network.getResponseBody", { requestId: params.requestId }, 1e4).then((result) => {
|
|
4568
|
-
|
|
4569
|
-
if (typeof
|
|
4755
|
+
partial2.responseBody = result.base64Encoded ? Buffer.from(result.body, "base64").toString("utf-8") : result.body;
|
|
4756
|
+
if (typeof partial2.responseBody === "string") {
|
|
4570
4757
|
try {
|
|
4571
|
-
|
|
4758
|
+
partial2.responseBody = JSON.parse(partial2.responseBody);
|
|
4572
4759
|
} catch {
|
|
4573
4760
|
}
|
|
4574
4761
|
}
|
|
4575
|
-
|
|
4762
|
+
refreshCapturedRequest(buffers, partial2);
|
|
4576
4763
|
}).catch(() => {
|
|
4577
4764
|
});
|
|
4578
|
-
appendRequestToBuffer(buffers.requests, buffers.requestBufferAccounting, req);
|
|
4579
4765
|
});
|
|
4580
4766
|
client2.on("Network.loadingFailed", (params) => {
|
|
4581
4767
|
const partial2 = buffers.pending.get(params.requestId);
|
|
4582
4768
|
if (!partial2) return;
|
|
4583
4769
|
buffers.pending.delete(params.requestId);
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
isPending: false
|
|
4590
|
-
};
|
|
4591
|
-
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);
|
|
4592
4775
|
});
|
|
4593
4776
|
client2.on("Runtime.consoleAPICalled", (params) => {
|
|
4594
|
-
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";
|
|
4595
4785
|
const args = (params.args ?? []).map((arg) => {
|
|
4596
4786
|
if (arg.type === "string") return arg.value;
|
|
4597
4787
|
if (arg.value !== void 0) return String(arg.value);
|
|
4598
4788
|
if (arg.description !== void 0) return arg.description;
|
|
4599
4789
|
return JSON.stringify(arg);
|
|
4600
4790
|
});
|
|
4601
|
-
|
|
4791
|
+
appendCapturedLog(buffers, {
|
|
4602
4792
|
level,
|
|
4603
4793
|
message: args.join(" "),
|
|
4604
|
-
|
|
4605
|
-
source: "console",
|
|
4606
|
-
args
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
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
|
+
});
|
|
4610
4816
|
});
|
|
4611
4817
|
client2.on("Log.entryAdded", (params) => {
|
|
4612
|
-
const entry = {
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4818
|
+
const entry = params.entry ?? {};
|
|
4819
|
+
const levelMap = {
|
|
4820
|
+
verbose: "log",
|
|
4821
|
+
info: "info",
|
|
4822
|
+
warning: "warn",
|
|
4823
|
+
error: "error"
|
|
4618
4824
|
};
|
|
4619
|
-
|
|
4620
|
-
|
|
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
|
+
});
|
|
4621
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
|
+
]);
|
|
4622
4847
|
}
|
|
4623
4848
|
|
|
4624
4849
|
// src/cdp-backend/discover.ts
|
|
@@ -4777,9 +5002,21 @@ var CdpSession = class {
|
|
|
4777
5002
|
} catch {
|
|
4778
5003
|
client2 = await CdpClient.connect(target.webSocketDebuggerUrl);
|
|
4779
5004
|
}
|
|
4780
|
-
|
|
4781
|
-
|
|
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);
|
|
4782
5018
|
const session = {
|
|
5019
|
+
tabId,
|
|
4783
5020
|
client: client2,
|
|
4784
5021
|
buffers,
|
|
4785
5022
|
targetId: target.id,
|
|
@@ -6035,6 +6272,143 @@ async function enrichCdpPageChangeSetWithRefs(session, observation) {
|
|
|
6035
6272
|
);
|
|
6036
6273
|
}
|
|
6037
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
|
+
|
|
6038
6412
|
// src/cdp-backend/composite-handlers.ts
|
|
6039
6413
|
async function cdpRunActions(session, data, controlSource = "local") {
|
|
6040
6414
|
const { actions, tabId } = data;
|
|
@@ -6110,21 +6484,42 @@ async function cdpRunActions(session, data, controlSource = "local") {
|
|
|
6110
6484
|
};
|
|
6111
6485
|
}
|
|
6112
6486
|
async function cdpObservedPageAction(session, action, data, controlSource = "local") {
|
|
6113
|
-
const { actionData, observe } = splitObservedActionPayload(data);
|
|
6114
|
-
if (observe === false) {
|
|
6115
|
-
return dispatchCdpAction(session, action, actionData, controlSource);
|
|
6116
|
-
}
|
|
6487
|
+
const { actionData, observe, diagnostics } = splitObservedActionPayload(action, data);
|
|
6117
6488
|
const { tabId } = actionData;
|
|
6118
6489
|
if (typeof tabId !== "number") throw new Error(`${action} requires a numeric tabId`);
|
|
6119
6490
|
const pageSession = await session.getPageSession(tabId);
|
|
6120
6491
|
await ensureControlledIndicator(pageSession, controlSource);
|
|
6121
|
-
|
|
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(
|
|
6122
6514
|
{ action, actionData, observe },
|
|
6123
6515
|
{
|
|
6124
6516
|
startObservation: () => startPageObservation(pageSession),
|
|
6125
6517
|
finishObservation: (checkpoint, options) => finishPageObservation(pageSession, checkpoint, options),
|
|
6126
6518
|
startNavigationObserver: (options) => startCdpNavigationObserver(session, pageSession, options.urlBefore, options),
|
|
6127
|
-
executeAction: (name, params) =>
|
|
6519
|
+
executeAction: (name, params) => {
|
|
6520
|
+
if (diagnostics) diagnosticsCursor = captureCheckpoint(pageSession.buffers.capture);
|
|
6521
|
+
return dispatchCdpAction(session, name, { ...params, tabId }, controlSource);
|
|
6522
|
+
},
|
|
6128
6523
|
finalizeObservation: (observation) => {
|
|
6129
6524
|
if (observation.mode === "delta") {
|
|
6130
6525
|
return enrichCdpPageChangeSetWithRefs(pageSession, observation);
|
|
@@ -6134,6 +6529,11 @@ async function cdpObservedPageAction(session, action, data, controlSource = "loc
|
|
|
6134
6529
|
disposeObservation: () => disposePageObservation(pageSession)
|
|
6135
6530
|
}
|
|
6136
6531
|
);
|
|
6532
|
+
if (!diagnostics || !diagnosticsCursor) return result;
|
|
6533
|
+
return {
|
|
6534
|
+
...result,
|
|
6535
|
+
diagnostics: await collectCdpPageDiagnostics(pageSession, diagnosticsCursor, diagnostics)
|
|
6536
|
+
};
|
|
6137
6537
|
}
|
|
6138
6538
|
registerActions([{ name: "run_actions", session: "browser", handler: cdpRunActions }]);
|
|
6139
6539
|
|
|
@@ -6721,112 +7121,6 @@ function listCloudConnectors() {
|
|
|
6721
7121
|
return { connectors: pushIfChanged() };
|
|
6722
7122
|
}
|
|
6723
7123
|
|
|
6724
|
-
// src/cdp-backend/request-handlers.ts
|
|
6725
|
-
function filterRequests(buffers, opts) {
|
|
6726
|
-
let requests = [...buffers.requests];
|
|
6727
|
-
if (opts.since !== void 0) {
|
|
6728
|
-
requests = requests.filter((r) => r.timestampMs >= opts.since);
|
|
6729
|
-
}
|
|
6730
|
-
if (opts.filter) {
|
|
6731
|
-
const pattern = compileTextPattern(opts.filter);
|
|
6732
|
-
requests = requests.filter(
|
|
6733
|
-
(r) => matchesTextPattern(r.url, pattern) || matchesTextPattern(r.apiName, pattern)
|
|
6734
|
-
);
|
|
6735
|
-
}
|
|
6736
|
-
if (opts.source === "mtop") {
|
|
6737
|
-
requests = requests.filter((r) => r.url?.includes("/h5/") || r.url?.includes("mtop"));
|
|
6738
|
-
}
|
|
6739
|
-
const count = opts.count ?? 10;
|
|
6740
|
-
return {
|
|
6741
|
-
requests: requests.slice(-count),
|
|
6742
|
-
totalMatched: requests.length
|
|
6743
|
-
};
|
|
6744
|
-
}
|
|
6745
|
-
async function cdpGetRequests(session, data) {
|
|
6746
|
-
const opts = {
|
|
6747
|
-
count: data.count ?? 10,
|
|
6748
|
-
filter: data.filter,
|
|
6749
|
-
since: data.since,
|
|
6750
|
-
source: data.source,
|
|
6751
|
-
applyHiddenFilter: data.applyHiddenFilter !== false
|
|
6752
|
-
};
|
|
6753
|
-
const { requests, totalMatched } = filterRequests(session.buffers, opts);
|
|
6754
|
-
const serializeOpts = {
|
|
6755
|
-
includeBody: data.includeBody !== false,
|
|
6756
|
-
includeHeaders: data.includeHeaders === true,
|
|
6757
|
-
maxBodySize: data.maxBodySize ?? 5e4,
|
|
6758
|
-
fields: data.fields,
|
|
6759
|
-
keysOnly: data.keysOnly === true
|
|
6760
|
-
};
|
|
6761
|
-
return {
|
|
6762
|
-
meta: {
|
|
6763
|
-
count: requests.length,
|
|
6764
|
-
totalMatched,
|
|
6765
|
-
totalInBuffer: session.buffers.requests.length,
|
|
6766
|
-
filter: data.filter,
|
|
6767
|
-
since: data.since,
|
|
6768
|
-
source: "cdp"
|
|
6769
|
-
},
|
|
6770
|
-
requests: requests.map((r) => serializeRequest(r, serializeOpts))
|
|
6771
|
-
};
|
|
6772
|
-
}
|
|
6773
|
-
async function cdpGetLogs(session, data) {
|
|
6774
|
-
const { level, since, limit = 100, filter } = data;
|
|
6775
|
-
let logs = [...session.buffers.logs];
|
|
6776
|
-
if (since !== void 0) {
|
|
6777
|
-
logs = logs.filter((l) => l.timestamp >= since);
|
|
6778
|
-
}
|
|
6779
|
-
if (level && level !== "all") {
|
|
6780
|
-
logs = logs.filter((l) => l.level === level);
|
|
6781
|
-
}
|
|
6782
|
-
if (filter) {
|
|
6783
|
-
const f = filter.toLowerCase();
|
|
6784
|
-
logs = logs.filter((l) => l.message?.toLowerCase().includes(f));
|
|
6785
|
-
}
|
|
6786
|
-
logs = logs.slice(-limit);
|
|
6787
|
-
return {
|
|
6788
|
-
meta: {
|
|
6789
|
-
count: logs.length,
|
|
6790
|
-
totalMatched: logs.length,
|
|
6791
|
-
level: level || "all",
|
|
6792
|
-
since,
|
|
6793
|
-
filter,
|
|
6794
|
-
source: "cdp"
|
|
6795
|
-
},
|
|
6796
|
-
logs
|
|
6797
|
-
};
|
|
6798
|
-
}
|
|
6799
|
-
async function cdpGetEvents(session, data) {
|
|
6800
|
-
const { source = "all", event_type, since, limit = 20, filter, includeRaw = false } = data;
|
|
6801
|
-
const response = queryTrackingEvents(session.buffers.events, {
|
|
6802
|
-
source,
|
|
6803
|
-
event_type,
|
|
6804
|
-
since,
|
|
6805
|
-
limit,
|
|
6806
|
-
filter
|
|
6807
|
-
});
|
|
6808
|
-
const captureStatus = response.totalInBuffer === 0 ? "armed" : "active";
|
|
6809
|
-
const hint = response.events.length === 0 && captureStatus === "armed" ? TRACKING_CAPTURE_ARMED_HINT : void 0;
|
|
6810
|
-
return {
|
|
6811
|
-
meta: {
|
|
6812
|
-
count: response.events.length,
|
|
6813
|
-
totalMatched: response.totalMatched,
|
|
6814
|
-
totalInBuffer: response.totalInBuffer,
|
|
6815
|
-
source,
|
|
6816
|
-
captureStatus,
|
|
6817
|
-
captureSource: "cdp",
|
|
6818
|
-
includeRaw,
|
|
6819
|
-
hint
|
|
6820
|
-
},
|
|
6821
|
-
events: response.events.map((event) => formatTrackingEvent(event, includeRaw))
|
|
6822
|
-
};
|
|
6823
|
-
}
|
|
6824
|
-
registerActions([
|
|
6825
|
-
{ name: "get_requests", session: "page", handler: cdpGetRequests },
|
|
6826
|
-
{ name: "get_logs", session: "page", handler: cdpGetLogs },
|
|
6827
|
-
{ name: "get_events", session: "page", handler: cdpGetEvents }
|
|
6828
|
-
]);
|
|
6829
|
-
|
|
6830
7124
|
// src/cdp-backend/send-request.ts
|
|
6831
7125
|
import { readFile } from "node:fs/promises";
|
|
6832
7126
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -6836,6 +7130,10 @@ function setHeader(headers, name, value) {
|
|
|
6836
7130
|
if (existing && existing !== name) delete headers[existing];
|
|
6837
7131
|
headers[name] = value;
|
|
6838
7132
|
}
|
|
7133
|
+
function removeHeader(headers, name) {
|
|
7134
|
+
const existing = findSendRequestHeaderName(headers, name);
|
|
7135
|
+
if (existing) delete headers[existing];
|
|
7136
|
+
}
|
|
6839
7137
|
function escapeMultipartQuotedValue(value) {
|
|
6840
7138
|
return value.replace(/\\/g, "\\\\").replace(/"/g, "%22");
|
|
6841
7139
|
}
|
|
@@ -6944,10 +7242,19 @@ async function executeNodeSendRequest(data, cookieMap = /* @__PURE__ */ new Map(
|
|
|
6944
7242
|
Accept: "application/json, text/plain, */*",
|
|
6945
7243
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
|
|
6946
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",
|
|
6947
|
-
Referer: targetUrl.origin + "/mearl",
|
|
6948
|
-
Origin: targetUrl.origin,
|
|
6949
7245
|
...headers
|
|
6950
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
|
+
}
|
|
6951
7258
|
const cookieHeader = [...cookieMap.entries()].map(([key, value]) => `${key}=${value}`).join("; ");
|
|
6952
7259
|
if (cookieHeader) setHeader(requestHeaders, "Cookie", cookieHeader);
|
|
6953
7260
|
const xsrfToken = cookieMap.get("XSRF-TOKEN");
|
|
@@ -7305,8 +7612,8 @@ registerActions([
|
|
|
7305
7612
|
]);
|
|
7306
7613
|
|
|
7307
7614
|
// src/cdp-backend/tdbank-handlers.ts
|
|
7308
|
-
async function cdpFetchTdbank(session,
|
|
7309
|
-
const url2 = new URL(`https://tdbank.alibaba-inc.com${
|
|
7615
|
+
async function cdpFetchTdbank(session, path15, options = {}) {
|
|
7616
|
+
const url2 = new URL(`https://tdbank.alibaba-inc.com${path15}`);
|
|
7310
7617
|
for (const [key, value] of Object.entries(options.params ?? {})) {
|
|
7311
7618
|
if (value !== void 0 && value !== null) {
|
|
7312
7619
|
url2.searchParams.set(key, String(value));
|
|
@@ -7574,6 +7881,14 @@ async function cdpTdbankAccount(cdpSession2, data) {
|
|
|
7574
7881
|
registerActions([{ name: "tdbank_account", session: "browser", handler: cdpTdbankAccount }]);
|
|
7575
7882
|
|
|
7576
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
|
+
}
|
|
7577
7892
|
async function cdpTabOpen(session, data, controlSource = "local") {
|
|
7578
7893
|
const { url: url2, active = false, emulation, reuse = "never", match } = data;
|
|
7579
7894
|
if (!url2 || typeof url2 !== "string") {
|
|
@@ -7600,12 +7915,14 @@ async function cdpTabOpen(session, data, controlSource = "local") {
|
|
|
7600
7915
|
const tabId2 = await session.ensureTargetRegistered(existing.targetId);
|
|
7601
7916
|
const pageSession2 = await session.getPageSession(tabId2);
|
|
7602
7917
|
await ensureControlledIndicator(pageSession2, controlSource);
|
|
7918
|
+
const capture2 = currentCapture(pageSession2);
|
|
7603
7919
|
return {
|
|
7604
7920
|
tabId: tabId2,
|
|
7605
7921
|
url: existing.url ?? url2,
|
|
7606
7922
|
title: existing.title ?? "",
|
|
7607
7923
|
opened: false,
|
|
7608
|
-
reused: true
|
|
7924
|
+
reused: true,
|
|
7925
|
+
capture: capture2
|
|
7609
7926
|
};
|
|
7610
7927
|
}
|
|
7611
7928
|
if (reuse === "require") {
|
|
@@ -7620,6 +7937,7 @@ async function cdpTabOpen(session, data, controlSource = "local") {
|
|
|
7620
7937
|
const tabId = await session.registerTarget(targetId);
|
|
7621
7938
|
const pageSession = await session.getPageSession(tabId);
|
|
7622
7939
|
await ensureControlledIndicator(pageSession, controlSource);
|
|
7940
|
+
const capture = currentCapture(pageSession);
|
|
7623
7941
|
if (emulationConfig) {
|
|
7624
7942
|
for (const { method, params } of buildEnableEmulationCommands(emulationConfig)) {
|
|
7625
7943
|
await pageSession.client.sendCommand(method, params);
|
|
@@ -7638,6 +7956,7 @@ async function cdpTabOpen(session, data, controlSource = "local") {
|
|
|
7638
7956
|
title: targetInfo?.title ?? "",
|
|
7639
7957
|
opened: true,
|
|
7640
7958
|
reused: false,
|
|
7959
|
+
capture,
|
|
7641
7960
|
...emulationConfig && {
|
|
7642
7961
|
emulation: {
|
|
7643
7962
|
preset: emulationConfig.presetName,
|
|
@@ -9433,7 +9752,7 @@ import os2 from "node:os";
|
|
|
9433
9752
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
9434
9753
|
|
|
9435
9754
|
// src/version.ts
|
|
9436
|
-
var NATIVE_HOST_VERSION = true ? "2.
|
|
9755
|
+
var NATIVE_HOST_VERSION = true ? "2.4.0" : "unknown";
|
|
9437
9756
|
|
|
9438
9757
|
// src/analytics.ts
|
|
9439
9758
|
var MEASUREMENT_ID = "G-W84LJDZ6PH";
|
|
@@ -10294,18 +10613,19 @@ var AgentChatManager = class {
|
|
|
10294
10613
|
|
|
10295
10614
|
// src/agent/codex-provider.ts
|
|
10296
10615
|
import os3 from "node:os";
|
|
10297
|
-
import path7 from "node:path";
|
|
10298
10616
|
import readline from "node:readline";
|
|
10299
10617
|
import { spawn as spawn6 } from "node:child_process";
|
|
10300
10618
|
|
|
10301
10619
|
// src/agent/executable-resolver.ts
|
|
10302
10620
|
import fs6 from "node:fs";
|
|
10303
10621
|
import { spawn as spawn5 } from "node:child_process";
|
|
10622
|
+
import path7 from "node:path";
|
|
10304
10623
|
|
|
10305
10624
|
// ../setup/dist/process.js
|
|
10306
10625
|
import fs5 from "node:fs";
|
|
10307
10626
|
import path6 from "node:path";
|
|
10308
10627
|
import { spawn as spawn4 } from "node:child_process";
|
|
10628
|
+
var MAX_CAPTURE_LENGTH = 1e6;
|
|
10309
10629
|
function isExecutable(filePath, platform = process.platform) {
|
|
10310
10630
|
try {
|
|
10311
10631
|
fs5.accessSync(filePath, platform === "win32" ? fs5.constants.F_OK : fs5.constants.X_OK);
|
|
@@ -10317,6 +10637,27 @@ function isExecutable(filePath, platform = process.platform) {
|
|
|
10317
10637
|
function executableNames(name, platform = process.platform) {
|
|
10318
10638
|
return platform === "win32" ? [`${name}.cmd`, `${name}.exe`, name] : [name];
|
|
10319
10639
|
}
|
|
10640
|
+
function versionManagerExecutableCandidates(home, names, options = {}) {
|
|
10641
|
+
const env = options.env ?? process.env;
|
|
10642
|
+
const platform = options.platform ?? process.platform;
|
|
10643
|
+
const readdirSync2 = options.readdirSync ?? fs5.readdirSync;
|
|
10644
|
+
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");
|
|
10645
|
+
const roots = [
|
|
10646
|
+
path6.join(env.NVM_DIR || path6.join(home, ".nvm"), "versions", "node"),
|
|
10647
|
+
path6.join(env.FNM_DIR || fnmDefaultRoot, "node-versions"),
|
|
10648
|
+
path6.join(home, ".fnm", "node-versions")
|
|
10649
|
+
].filter((root, index, all) => all.indexOf(root) === index);
|
|
10650
|
+
return roots.flatMap((root) => {
|
|
10651
|
+
try {
|
|
10652
|
+
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) => [
|
|
10653
|
+
path6.join(root, entry.name, "bin", name),
|
|
10654
|
+
path6.join(root, entry.name, "installation", "bin", name)
|
|
10655
|
+
]));
|
|
10656
|
+
} catch {
|
|
10657
|
+
return [];
|
|
10658
|
+
}
|
|
10659
|
+
});
|
|
10660
|
+
}
|
|
10320
10661
|
function resolveSpawnCommand(executable, args, platform = process.platform, commandInterpreter = process.env.ComSpec) {
|
|
10321
10662
|
if (platform === "win32" && /\.(?:cmd|bat)$/i.test(executable)) {
|
|
10322
10663
|
return {
|
|
@@ -10329,12 +10670,12 @@ function resolveSpawnCommand(executable, args, platform = process.platform, comm
|
|
|
10329
10670
|
function prependCommandPath(command, env = process.env) {
|
|
10330
10671
|
if (!path6.isAbsolute(command))
|
|
10331
10672
|
return env;
|
|
10332
|
-
return
|
|
10673
|
+
return prependPathDirectory(path6.dirname(command), env);
|
|
10333
10674
|
}
|
|
10334
10675
|
function prependNodePath(env = process.env, nodeExecutable = process.execPath) {
|
|
10335
|
-
return
|
|
10676
|
+
return prependPathDirectory(path6.dirname(nodeExecutable), env);
|
|
10336
10677
|
}
|
|
10337
|
-
function
|
|
10678
|
+
function prependPathDirectory(directory, env = process.env) {
|
|
10338
10679
|
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
10339
10680
|
const inherited = env[pathKey] || "";
|
|
10340
10681
|
const entries = inherited.split(path6.delimiter).filter(Boolean);
|
|
@@ -10342,8 +10683,101 @@ function prependPath(directory, env) {
|
|
|
10342
10683
|
return env;
|
|
10343
10684
|
return { ...env, [pathKey]: [directory, ...entries].join(path6.delimiter) };
|
|
10344
10685
|
}
|
|
10686
|
+
function findExecutable(name, options = {}) {
|
|
10687
|
+
const env = options.env ?? process.env;
|
|
10688
|
+
const platform = options.platform ?? process.platform;
|
|
10689
|
+
const existsSync4 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
|
|
10690
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
10691
|
+
const directories = [
|
|
10692
|
+
...options.extraDirectories ?? [],
|
|
10693
|
+
...(env[pathKey] ?? "").split(path6.delimiter).filter(Boolean)
|
|
10694
|
+
];
|
|
10695
|
+
for (const directory of directories) {
|
|
10696
|
+
for (const executableName of executableNames(name, platform)) {
|
|
10697
|
+
const candidate = path6.join(directory, executableName);
|
|
10698
|
+
if (existsSync4(candidate))
|
|
10699
|
+
return candidate;
|
|
10700
|
+
}
|
|
10701
|
+
}
|
|
10702
|
+
return null;
|
|
10703
|
+
}
|
|
10704
|
+
var runCommand = (command, args, options = {}) => new Promise((resolve, reject) => {
|
|
10705
|
+
const capture = options.capture === true;
|
|
10706
|
+
const launch = resolveSpawnCommand(command, args);
|
|
10707
|
+
const child = spawn4(launch.command, launch.args, {
|
|
10708
|
+
cwd: options.cwd,
|
|
10709
|
+
env: options.env,
|
|
10710
|
+
stdio: capture ? ["ignore", "pipe", "pipe"] : "inherit",
|
|
10711
|
+
windowsHide: true
|
|
10712
|
+
});
|
|
10713
|
+
let stdout = "";
|
|
10714
|
+
let stderr = "";
|
|
10715
|
+
let settled = false;
|
|
10716
|
+
const append = (current, chunk) => current.length >= MAX_CAPTURE_LENGTH ? current : (current + chunk.toString("utf8")).slice(0, MAX_CAPTURE_LENGTH);
|
|
10717
|
+
const finish = (error48, code = 1) => {
|
|
10718
|
+
if (settled)
|
|
10719
|
+
return;
|
|
10720
|
+
settled = true;
|
|
10721
|
+
if (timer)
|
|
10722
|
+
clearTimeout(timer);
|
|
10723
|
+
if (error48)
|
|
10724
|
+
reject(error48);
|
|
10725
|
+
else
|
|
10726
|
+
resolve({ code, stdout, stderr });
|
|
10727
|
+
};
|
|
10728
|
+
const timer = options.timeoutMs === void 0 ? void 0 : setTimeout(() => {
|
|
10729
|
+
child.kill("SIGTERM");
|
|
10730
|
+
finish(new Error(`Command timed out after ${options.timeoutMs}ms`));
|
|
10731
|
+
}, options.timeoutMs);
|
|
10732
|
+
if (capture) {
|
|
10733
|
+
child.stdout?.on("data", (chunk) => stdout = append(stdout, chunk));
|
|
10734
|
+
child.stderr?.on("data", (chunk) => stderr = append(stderr, chunk));
|
|
10735
|
+
}
|
|
10736
|
+
child.once("error", (error48) => finish(error48));
|
|
10737
|
+
child.once("close", (code) => finish(void 0, code ?? 1));
|
|
10738
|
+
});
|
|
10345
10739
|
|
|
10346
10740
|
// src/agent/executable-resolver.ts
|
|
10741
|
+
function agentExecutableCandidatePaths({
|
|
10742
|
+
executableNames: executableNames2,
|
|
10743
|
+
configuredPath,
|
|
10744
|
+
env = process.env,
|
|
10745
|
+
extraUserCandidates = [],
|
|
10746
|
+
home,
|
|
10747
|
+
platform = process.platform,
|
|
10748
|
+
processExecPath = process.execPath,
|
|
10749
|
+
readdirSync: readdirSync2
|
|
10750
|
+
}) {
|
|
10751
|
+
const pathKey = Object.keys(env).find((key) => key.toLowerCase() === "path") || "PATH";
|
|
10752
|
+
const pathCandidates = (env[pathKey] || "").split(path7.delimiter).filter(Boolean).flatMap((directory) => executableNames2.map((name) => path7.join(directory, name)));
|
|
10753
|
+
const commonUserDirectories = [
|
|
10754
|
+
path7.join(home, ".local", "bin"),
|
|
10755
|
+
path7.join(home, ".npm-global", "bin"),
|
|
10756
|
+
path7.join(home, ".volta", "bin"),
|
|
10757
|
+
path7.join(home, ".local", "share", "pnpm"),
|
|
10758
|
+
path7.join(home, "Library", "pnpm"),
|
|
10759
|
+
path7.join(home, ".bun", "bin"),
|
|
10760
|
+
...platform === "win32" && env.APPDATA ? [path7.join(env.APPDATA, "npm")] : []
|
|
10761
|
+
];
|
|
10762
|
+
const systemDirectories = platform === "win32" ? [] : ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin"];
|
|
10763
|
+
return [
|
|
10764
|
+
configuredPath,
|
|
10765
|
+
...executableNames2.map((name) => path7.join(path7.dirname(processExecPath), name)),
|
|
10766
|
+
...commonUserDirectories.flatMap(
|
|
10767
|
+
(directory) => executableNames2.map((name) => path7.join(directory, name))
|
|
10768
|
+
),
|
|
10769
|
+
...extraUserCandidates,
|
|
10770
|
+
...versionManagerExecutableCandidates(home, executableNames2, {
|
|
10771
|
+
env,
|
|
10772
|
+
platform,
|
|
10773
|
+
readdirSync: readdirSync2
|
|
10774
|
+
}),
|
|
10775
|
+
...systemDirectories.flatMap(
|
|
10776
|
+
(directory) => executableNames2.map((name) => path7.join(directory, name))
|
|
10777
|
+
),
|
|
10778
|
+
...pathCandidates
|
|
10779
|
+
].filter((candidate) => typeof candidate === "string");
|
|
10780
|
+
}
|
|
10347
10781
|
var AgentExecutableResolver = class {
|
|
10348
10782
|
constructor(options) {
|
|
10349
10783
|
this.options = options;
|
|
@@ -10457,6 +10891,21 @@ var REQUEST_TIMEOUT_MS = 3e4;
|
|
|
10457
10891
|
var PROBE_TIMEOUT_MS = 5e3;
|
|
10458
10892
|
var MAX_MODEL_CHARS = 256;
|
|
10459
10893
|
var CODEX_NOT_FOUND_ERROR = "Codex CLI was not found. Install @openai/codex or set MEARL_CODEX_PATH.";
|
|
10894
|
+
function codexExecutableCandidatePaths(options = {}) {
|
|
10895
|
+
const env = options.env ?? process.env;
|
|
10896
|
+
const home = (options.homedir ?? os3.homedir)();
|
|
10897
|
+
const platform = options.platform ?? process.platform;
|
|
10898
|
+
const executableName = platform === "win32" ? "codex.cmd" : "codex";
|
|
10899
|
+
return agentExecutableCandidatePaths({
|
|
10900
|
+
executableNames: [executableName],
|
|
10901
|
+
configuredPath: env.MEARL_CODEX_PATH,
|
|
10902
|
+
env,
|
|
10903
|
+
home,
|
|
10904
|
+
platform,
|
|
10905
|
+
processExecPath: options.processExecPath,
|
|
10906
|
+
readdirSync: options.readdirSync
|
|
10907
|
+
});
|
|
10908
|
+
}
|
|
10460
10909
|
function codexModelInfo(value) {
|
|
10461
10910
|
if (typeof value !== "string") return void 0;
|
|
10462
10911
|
const id = value.trim().slice(0, MAX_MODEL_CHARS);
|
|
@@ -10938,18 +11387,7 @@ var CodexAgentProvider = class {
|
|
|
10938
11387
|
return this.executableResolver.resolve();
|
|
10939
11388
|
}
|
|
10940
11389
|
resolveExecutableCandidates() {
|
|
10941
|
-
|
|
10942
|
-
const configured = process.env.MEARL_CODEX_PATH;
|
|
10943
|
-
const pathCandidates = (process.env.PATH || "").split(path7.delimiter).filter(Boolean).map((dir) => path7.join(dir, executableName));
|
|
10944
|
-
return executableFileCandidates([
|
|
10945
|
-
configured,
|
|
10946
|
-
path7.join(path7.dirname(process.execPath), executableName),
|
|
10947
|
-
path7.join(os3.homedir(), ".local", "bin", executableName),
|
|
10948
|
-
path7.join(os3.homedir(), ".npm-global", "bin", executableName),
|
|
10949
|
-
path7.join(os3.homedir(), ".volta", "bin", executableName),
|
|
10950
|
-
...process.platform === "win32" ? [] : ["/opt/homebrew/bin/codex", "/usr/local/bin/codex", "/usr/bin/codex"],
|
|
10951
|
-
...pathCandidates
|
|
10952
|
-
]);
|
|
11390
|
+
return executableFileCandidates(codexExecutableCandidatePaths());
|
|
10953
11391
|
}
|
|
10954
11392
|
};
|
|
10955
11393
|
|
|
@@ -11779,10 +12217,10 @@ function mergeDefs(...defs) {
|
|
|
11779
12217
|
function cloneDef(schema) {
|
|
11780
12218
|
return mergeDefs(schema._zod.def);
|
|
11781
12219
|
}
|
|
11782
|
-
function getElementAtPath(obj,
|
|
11783
|
-
if (!
|
|
12220
|
+
function getElementAtPath(obj, path15) {
|
|
12221
|
+
if (!path15)
|
|
11784
12222
|
return obj;
|
|
11785
|
-
return
|
|
12223
|
+
return path15.reduce((acc, key) => acc?.[key], obj);
|
|
11786
12224
|
}
|
|
11787
12225
|
function promiseAllObject(promisesObj) {
|
|
11788
12226
|
const keys = Object.keys(promisesObj);
|
|
@@ -12165,11 +12603,11 @@ function aborted(x, startIndex = 0) {
|
|
|
12165
12603
|
}
|
|
12166
12604
|
return false;
|
|
12167
12605
|
}
|
|
12168
|
-
function prefixIssues(
|
|
12606
|
+
function prefixIssues(path15, issues) {
|
|
12169
12607
|
return issues.map((iss) => {
|
|
12170
12608
|
var _a2;
|
|
12171
12609
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
12172
|
-
iss.path.unshift(
|
|
12610
|
+
iss.path.unshift(path15);
|
|
12173
12611
|
return iss;
|
|
12174
12612
|
});
|
|
12175
12613
|
}
|
|
@@ -12352,7 +12790,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
12352
12790
|
}
|
|
12353
12791
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
12354
12792
|
const result = { errors: [] };
|
|
12355
|
-
const processError = (error49,
|
|
12793
|
+
const processError = (error49, path15 = []) => {
|
|
12356
12794
|
var _a2, _b;
|
|
12357
12795
|
for (const issue2 of error49.issues) {
|
|
12358
12796
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -12362,7 +12800,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
12362
12800
|
} else if (issue2.code === "invalid_element") {
|
|
12363
12801
|
processError({ issues: issue2.issues }, issue2.path);
|
|
12364
12802
|
} else {
|
|
12365
|
-
const fullpath = [...
|
|
12803
|
+
const fullpath = [...path15, ...issue2.path];
|
|
12366
12804
|
if (fullpath.length === 0) {
|
|
12367
12805
|
result.errors.push(mapper(issue2));
|
|
12368
12806
|
continue;
|
|
@@ -12394,8 +12832,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
12394
12832
|
}
|
|
12395
12833
|
function toDotPath(_path) {
|
|
12396
12834
|
const segs = [];
|
|
12397
|
-
const
|
|
12398
|
-
for (const seg of
|
|
12835
|
+
const path15 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
12836
|
+
for (const seg of path15) {
|
|
12399
12837
|
if (typeof seg === "number")
|
|
12400
12838
|
segs.push(`[${seg}]`);
|
|
12401
12839
|
else if (typeof seg === "symbol")
|
|
@@ -24372,13 +24810,13 @@ function resolveRef(ref, ctx) {
|
|
|
24372
24810
|
if (!ref.startsWith("#")) {
|
|
24373
24811
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
24374
24812
|
}
|
|
24375
|
-
const
|
|
24376
|
-
if (
|
|
24813
|
+
const path15 = ref.slice(1).split("/").filter(Boolean);
|
|
24814
|
+
if (path15.length === 0) {
|
|
24377
24815
|
return ctx.rootSchema;
|
|
24378
24816
|
}
|
|
24379
24817
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
24380
|
-
if (
|
|
24381
|
-
const key =
|
|
24818
|
+
if (path15[0] === defsKey) {
|
|
24819
|
+
const key = path15[1];
|
|
24382
24820
|
if (!key || !ctx.defs[key]) {
|
|
24383
24821
|
throw new Error(`Reference not found: ${ref}`);
|
|
24384
24822
|
}
|
|
@@ -28303,10 +28741,10 @@ function parseQoderSkillsList(output, cwd, home = os4.homedir()) {
|
|
|
28303
28741
|
finish();
|
|
28304
28742
|
return skills;
|
|
28305
28743
|
}
|
|
28306
|
-
function qoderManagedExecutableCandidates(home) {
|
|
28744
|
+
function qoderManagedExecutableCandidates(home, readdirSync2 = fs7.readdirSync) {
|
|
28307
28745
|
const directory = path8.join(home, ".qoder", "bin", "qodercli");
|
|
28308
28746
|
try {
|
|
28309
|
-
return
|
|
28747
|
+
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));
|
|
28310
28748
|
} catch {
|
|
28311
28749
|
return [];
|
|
28312
28750
|
}
|
|
@@ -28321,6 +28759,25 @@ function isPermissionResponse(value) {
|
|
|
28321
28759
|
function qoderInstallCommand(platform = process.platform) {
|
|
28322
28760
|
return platform === "win32" ? "npm install -g @qoder-ai/qodercli" : "curl -fsSL https://qoder.com/install | bash";
|
|
28323
28761
|
}
|
|
28762
|
+
function qoderExecutableCandidatePaths(options = {}) {
|
|
28763
|
+
const env = options.env ?? process.env;
|
|
28764
|
+
const home = (options.homedir ?? os4.homedir)();
|
|
28765
|
+
const platform = options.platform ?? process.platform;
|
|
28766
|
+
const executableNames2 = platform === "win32" ? ["qodercli.exe", "qodercli.cmd"] : ["qodercli"];
|
|
28767
|
+
return agentExecutableCandidatePaths({
|
|
28768
|
+
executableNames: executableNames2,
|
|
28769
|
+
configuredPath: env.MEARL_QODER_PATH,
|
|
28770
|
+
env,
|
|
28771
|
+
extraUserCandidates: [
|
|
28772
|
+
...qoderManagedExecutableCandidates(home, options.readdirSync),
|
|
28773
|
+
...executableNames2.map((name) => path8.join(home, ".qoder", "bin", name))
|
|
28774
|
+
],
|
|
28775
|
+
home,
|
|
28776
|
+
platform,
|
|
28777
|
+
processExecPath: options.processExecPath,
|
|
28778
|
+
readdirSync: options.readdirSync
|
|
28779
|
+
});
|
|
28780
|
+
}
|
|
28324
28781
|
function sessionOptions(options) {
|
|
28325
28782
|
const cwd = path8.resolve(options.cwd || os4.homedir());
|
|
28326
28783
|
return {
|
|
@@ -29112,19 +29569,7 @@ ${message}` : message;
|
|
|
29112
29569
|
return this.executableResolver.resolve();
|
|
29113
29570
|
}
|
|
29114
29571
|
resolveExecutableCandidates() {
|
|
29115
|
-
|
|
29116
|
-
const configured = process.env.MEARL_QODER_PATH;
|
|
29117
|
-
const home = os4.homedir();
|
|
29118
|
-
const pathCandidates = (process.env.PATH || "").split(path8.delimiter).filter(Boolean).flatMap((dir) => executableNames2.map((name) => path8.join(dir, name)));
|
|
29119
|
-
return executableFileCandidates([
|
|
29120
|
-
configured,
|
|
29121
|
-
...executableNames2.map((name) => path8.join(path8.dirname(process.execPath), name)),
|
|
29122
|
-
...executableNames2.map((name) => path8.join(home, ".local", "bin", name)),
|
|
29123
|
-
...qoderManagedExecutableCandidates(home),
|
|
29124
|
-
...executableNames2.map((name) => path8.join(home, ".qoder", "bin", name)),
|
|
29125
|
-
...process.platform === "win32" ? [] : ["/opt/homebrew/bin/qodercli", "/usr/local/bin/qodercli", "/usr/bin/qodercli"],
|
|
29126
|
-
...pathCandidates
|
|
29127
|
-
]);
|
|
29572
|
+
return executableFileCandidates(qoderExecutableCandidatePaths());
|
|
29128
29573
|
}
|
|
29129
29574
|
emit(event) {
|
|
29130
29575
|
for (const listener of this.listeners) listener(event);
|
|
@@ -29142,22 +29587,6 @@ var ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\u001B\[[0-?]*[ -/]*[@-~]`, "g")
|
|
|
29142
29587
|
function existingExecutable(candidates, existsSync4) {
|
|
29143
29588
|
return candidates.find((candidate) => candidate && existsSync4(candidate)) ?? null;
|
|
29144
29589
|
}
|
|
29145
|
-
function versionManagerCandidates(home, executableNames2, readdirSync2) {
|
|
29146
|
-
const roots = [
|
|
29147
|
-
path9.join(home, ".nvm", "versions", "node"),
|
|
29148
|
-
path9.join(home, ".fnm", "node-versions")
|
|
29149
|
-
];
|
|
29150
|
-
return roots.flatMap((root) => {
|
|
29151
|
-
try {
|
|
29152
|
-
return readdirSync2(root, { withFileTypes: true }).filter((entry) => entry.isDirectory()).sort((left, right) => right.name.localeCompare(left.name, void 0, { numeric: true })).flatMap((entry) => executableNames2.flatMap((name) => [
|
|
29153
|
-
path9.join(root, entry.name, "bin", name),
|
|
29154
|
-
path9.join(root, entry.name, "installation", "bin", name)
|
|
29155
|
-
]));
|
|
29156
|
-
} catch {
|
|
29157
|
-
return [];
|
|
29158
|
-
}
|
|
29159
|
-
});
|
|
29160
|
-
}
|
|
29161
29590
|
function stripAnsi(value) {
|
|
29162
29591
|
return value.replace(ANSI_ESCAPE_PATTERN, "");
|
|
29163
29592
|
}
|
|
@@ -29179,7 +29608,11 @@ function resolveAliSkillsExecutable(options = {}) {
|
|
|
29179
29608
|
...names.map((name) => path9.join(home, ".volta", "bin", name)),
|
|
29180
29609
|
...names.map((name) => path9.join(home, ".local", "share", "pnpm", name)),
|
|
29181
29610
|
...names.map((name) => path9.join(home, "Library", "pnpm", name)),
|
|
29182
|
-
...
|
|
29611
|
+
...versionManagerExecutableCandidates(home, names, {
|
|
29612
|
+
env,
|
|
29613
|
+
platform,
|
|
29614
|
+
readdirSync: readdirSync2
|
|
29615
|
+
}),
|
|
29183
29616
|
...platform === "win32" ? [] : ["/opt/homebrew/bin/ali-skills", "/usr/local/bin/ali-skills", "/usr/bin/ali-skills"],
|
|
29184
29617
|
...pathCandidates
|
|
29185
29618
|
];
|
|
@@ -29390,6 +29823,409 @@ function createExtensionRequestMessage(id, action, data, trustedInternal = false
|
|
|
29390
29823
|
};
|
|
29391
29824
|
}
|
|
29392
29825
|
|
|
29826
|
+
// src/host-updater.ts
|
|
29827
|
+
import fs10 from "node:fs";
|
|
29828
|
+
import path11 from "node:path";
|
|
29829
|
+
import { fileURLToPath } from "node:url";
|
|
29830
|
+
|
|
29831
|
+
// ../setup/dist/packageManager.js
|
|
29832
|
+
import fs9 from "node:fs";
|
|
29833
|
+
import path10 from "node:path";
|
|
29834
|
+
function normalizePath(filePath) {
|
|
29835
|
+
return filePath.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
29836
|
+
}
|
|
29837
|
+
function firstExisting(candidates, existsSync4) {
|
|
29838
|
+
return candidates.find((candidate) => existsSync4(candidate));
|
|
29839
|
+
}
|
|
29840
|
+
function fallbackCommand(name, platform) {
|
|
29841
|
+
if (platform !== "win32")
|
|
29842
|
+
return name;
|
|
29843
|
+
if (name === "bun" || name === "volta")
|
|
29844
|
+
return `${name}.exe`;
|
|
29845
|
+
return `${name}.cmd`;
|
|
29846
|
+
}
|
|
29847
|
+
function resolvePackageManagerInstallation(packageRoot, packageName, options = {}) {
|
|
29848
|
+
const env = options.env ?? process.env;
|
|
29849
|
+
const platform = options.platform ?? process.platform;
|
|
29850
|
+
const existsSync4 = options.existsSync ?? ((candidate) => isExecutable(candidate, platform));
|
|
29851
|
+
const processExecPath = options.processExecPath ?? process.execPath;
|
|
29852
|
+
const normalizedRoot = normalizePath(path10.resolve(packageRoot));
|
|
29853
|
+
const lowerRoot = normalizedRoot.toLowerCase();
|
|
29854
|
+
const lowerPackageName = packageName.toLowerCase();
|
|
29855
|
+
const pnpmGlobalRoot = /\/global\/\d+\/(?:\.pnpm\/.*\/)?node_modules\//.exec(lowerRoot);
|
|
29856
|
+
if (pnpmGlobalRoot && lowerRoot.endsWith(`/node_modules/${lowerPackageName}`)) {
|
|
29857
|
+
const pnpmHome = normalizedRoot.slice(0, pnpmGlobalRoot.index);
|
|
29858
|
+
const command = firstExisting([
|
|
29859
|
+
...executableNames("pnpm", platform).map((name) => path10.join(pnpmHome, name)),
|
|
29860
|
+
...executableNames("pnpm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29861
|
+
], existsSync4) ?? fallbackCommand("pnpm", platform);
|
|
29862
|
+
return { manager: "pnpm", command, binDirectory: pnpmHome };
|
|
29863
|
+
}
|
|
29864
|
+
const bunMarker = `/.bun/install/global/node_modules/${lowerPackageName}`;
|
|
29865
|
+
if (lowerRoot.endsWith(bunMarker)) {
|
|
29866
|
+
const bunHome = normalizedRoot.slice(0, lowerRoot.indexOf("/.bun/"));
|
|
29867
|
+
const command = firstExisting(executableNames("bun", platform).map((name) => path10.join(bunHome, ".bun", "bin", name)), existsSync4) ?? fallbackCommand("bun", platform);
|
|
29868
|
+
return {
|
|
29869
|
+
manager: "bun",
|
|
29870
|
+
command,
|
|
29871
|
+
binDirectory: path10.join(bunHome, ".bun", "bin")
|
|
29872
|
+
};
|
|
29873
|
+
}
|
|
29874
|
+
if ((lowerRoot.includes("/.config/yarn/global/node_modules/") || lowerRoot.includes("/.yarn/global/node_modules/") || lowerRoot.includes("/yarn/global/node_modules/") || lowerRoot.includes("/yarn/data/global/node_modules/")) && lowerRoot.endsWith(`/node_modules/${lowerPackageName}`)) {
|
|
29875
|
+
const layout = [
|
|
29876
|
+
{ marker: "/.config/yarn/global/", binSegments: [".yarn", "bin"] },
|
|
29877
|
+
{ marker: "/.yarn/global/", binSegments: [".yarn", "bin"] },
|
|
29878
|
+
{ marker: "/yarn/data/global/", binSegments: ["yarn", "bin"] },
|
|
29879
|
+
{ marker: "/yarn/global/", binSegments: ["yarn", "bin"] }
|
|
29880
|
+
].find((candidate) => lowerRoot.includes(candidate.marker));
|
|
29881
|
+
const prefix = normalizedRoot.slice(0, lowerRoot.indexOf(layout.marker));
|
|
29882
|
+
const binDirectory = path10.join(prefix, ...layout.binSegments);
|
|
29883
|
+
const command = firstExisting([
|
|
29884
|
+
...executableNames("yarn", platform).map((name) => path10.join(binDirectory, name)),
|
|
29885
|
+
...executableNames("yarn", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29886
|
+
], existsSync4) ?? findExecutable("yarn", { env, existsSync: existsSync4, platform }) ?? fallbackCommand("yarn", platform);
|
|
29887
|
+
return { manager: "yarn", command, binDirectory };
|
|
29888
|
+
}
|
|
29889
|
+
if (lowerRoot.includes("/.volta/tools/image/packages/") && lowerRoot.endsWith(`/lib/node_modules/${lowerPackageName}`)) {
|
|
29890
|
+
const voltaHome = normalizedRoot.slice(0, lowerRoot.indexOf("/.volta/"));
|
|
29891
|
+
const command = firstExisting(executableNames("volta", platform).map((name) => path10.join(voltaHome, ".volta", "bin", name)), existsSync4) ?? fallbackCommand("volta", platform);
|
|
29892
|
+
return {
|
|
29893
|
+
manager: "volta",
|
|
29894
|
+
command,
|
|
29895
|
+
binDirectory: path10.join(voltaHome, ".volta", "bin")
|
|
29896
|
+
};
|
|
29897
|
+
}
|
|
29898
|
+
const npmMarker = `/lib/node_modules/${lowerPackageName}`;
|
|
29899
|
+
if (lowerRoot.endsWith(npmMarker)) {
|
|
29900
|
+
const prefix = normalizedRoot.slice(0, lowerRoot.length - npmMarker.length);
|
|
29901
|
+
const command = firstExisting([
|
|
29902
|
+
...executableNames("npm", platform).map((name) => path10.join(prefix, "bin", name)),
|
|
29903
|
+
...executableNames("npm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29904
|
+
], existsSync4) ?? fallbackCommand("npm", platform);
|
|
29905
|
+
return { manager: "npm", command, binDirectory: path10.join(prefix, "bin") };
|
|
29906
|
+
}
|
|
29907
|
+
if (platform === "win32" && env.APPDATA) {
|
|
29908
|
+
const npmRoot = normalizePath(path10.join(env.APPDATA, "npm", "node_modules", packageName));
|
|
29909
|
+
if (lowerRoot === npmRoot.toLowerCase()) {
|
|
29910
|
+
const binDirectory = path10.join(env.APPDATA, "npm");
|
|
29911
|
+
const command = firstExisting([
|
|
29912
|
+
...executableNames("npm", platform).map((name) => path10.join(binDirectory, name)),
|
|
29913
|
+
...executableNames("npm", platform).map((name) => path10.join(path10.dirname(processExecPath), name))
|
|
29914
|
+
], existsSync4) ?? fallbackCommand("npm", platform);
|
|
29915
|
+
return { manager: "npm", command, binDirectory };
|
|
29916
|
+
}
|
|
29917
|
+
}
|
|
29918
|
+
return null;
|
|
29919
|
+
}
|
|
29920
|
+
|
|
29921
|
+
// ../setup/dist/version.js
|
|
29922
|
+
var MEARL_RELEASE_VERSION_MAX_LENGTH = 64;
|
|
29923
|
+
var RELEASE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-beta\.(0|[1-9]\d*))?$/;
|
|
29924
|
+
var RELEASE_LINE_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.x$/;
|
|
29925
|
+
var RELEASE_COMPONENT_MAXIMUM = 65535;
|
|
29926
|
+
function parseComponent(value) {
|
|
29927
|
+
const component = Number(value);
|
|
29928
|
+
return Number.isSafeInteger(component) && component <= RELEASE_COMPONENT_MAXIMUM ? component : null;
|
|
29929
|
+
}
|
|
29930
|
+
function parseMearlReleaseVersion(value) {
|
|
29931
|
+
if (typeof value !== "string" || value.length > MEARL_RELEASE_VERSION_MAX_LENGTH)
|
|
29932
|
+
return null;
|
|
29933
|
+
const match = RELEASE_VERSION_PATTERN.exec(value);
|
|
29934
|
+
if (!match)
|
|
29935
|
+
return null;
|
|
29936
|
+
const major = parseComponent(match[1]);
|
|
29937
|
+
const minor = parseComponent(match[2]);
|
|
29938
|
+
const patch = parseComponent(match[3]);
|
|
29939
|
+
const beta = match[4] === void 0 ? void 0 : parseComponent(match[4]);
|
|
29940
|
+
if (major === null || minor === null || patch === null || beta === null)
|
|
29941
|
+
return null;
|
|
29942
|
+
return {
|
|
29943
|
+
raw: value,
|
|
29944
|
+
major,
|
|
29945
|
+
minor,
|
|
29946
|
+
patch,
|
|
29947
|
+
channel: beta === void 0 ? "stable" : "beta",
|
|
29948
|
+
...beta === void 0 ? {} : { beta }
|
|
29949
|
+
};
|
|
29950
|
+
}
|
|
29951
|
+
function isMearlReleaseVersion(value) {
|
|
29952
|
+
return parseMearlReleaseVersion(value) !== null;
|
|
29953
|
+
}
|
|
29954
|
+
function parseMearlReleaseLine(value) {
|
|
29955
|
+
if (typeof value !== "string" || value.length > MEARL_RELEASE_VERSION_MAX_LENGTH)
|
|
29956
|
+
return null;
|
|
29957
|
+
const match = RELEASE_LINE_PATTERN.exec(value);
|
|
29958
|
+
if (!match)
|
|
29959
|
+
return null;
|
|
29960
|
+
const major = parseComponent(match[1]);
|
|
29961
|
+
const minor = parseComponent(match[2]);
|
|
29962
|
+
if (major === null || minor === null)
|
|
29963
|
+
return null;
|
|
29964
|
+
return { raw: value, major, minor };
|
|
29965
|
+
}
|
|
29966
|
+
function mearlReleaseLineForVersion(version2) {
|
|
29967
|
+
const parsed = parseMearlReleaseVersion(version2);
|
|
29968
|
+
if (!parsed)
|
|
29969
|
+
throw new Error("A valid Mearl release version is required");
|
|
29970
|
+
return `${parsed.major}.${parsed.minor}.x`;
|
|
29971
|
+
}
|
|
29972
|
+
function isMearlReleaseVersionInLine(version2, releaseLine) {
|
|
29973
|
+
const parsedVersion = parseMearlReleaseVersion(version2);
|
|
29974
|
+
const parsedLine = parseMearlReleaseLine(releaseLine);
|
|
29975
|
+
return parsedVersion !== null && parsedLine !== null && parsedVersion.major === parsedLine.major && parsedVersion.minor === parsedLine.minor;
|
|
29976
|
+
}
|
|
29977
|
+
function compareMearlReleaseLines(leftVersion, rightVersion) {
|
|
29978
|
+
const left = parseMearlReleaseVersion(leftVersion);
|
|
29979
|
+
const right = parseMearlReleaseVersion(rightVersion);
|
|
29980
|
+
if (!left || !right) {
|
|
29981
|
+
throw new Error("Mearl release-line comparison requires valid release versions");
|
|
29982
|
+
}
|
|
29983
|
+
for (const key of ["major", "minor"]) {
|
|
29984
|
+
if (left[key] < right[key])
|
|
29985
|
+
return -1;
|
|
29986
|
+
if (left[key] > right[key])
|
|
29987
|
+
return 1;
|
|
29988
|
+
}
|
|
29989
|
+
return 0;
|
|
29990
|
+
}
|
|
29991
|
+
|
|
29992
|
+
// src/host-updater.ts
|
|
29993
|
+
var NATIVE_HOST_UPDATE_TIMEOUT_MS = 5 * 6e4;
|
|
29994
|
+
var UPDATE_LOCK_PATH = path11.join(DAEMON_HOME, "native-host-update.lock");
|
|
29995
|
+
var UPDATE_LOCK_POLL_MS = 500;
|
|
29996
|
+
var INVALID_UPDATE_LOCK_GRACE_MS = 1e4;
|
|
29997
|
+
var NativeHostUpdateFailure = class extends Error {
|
|
29998
|
+
constructor(updateError, message) {
|
|
29999
|
+
super(message);
|
|
30000
|
+
this.updateError = updateError;
|
|
30001
|
+
this.name = "NativeHostUpdateFailure";
|
|
30002
|
+
}
|
|
30003
|
+
};
|
|
30004
|
+
function wait(delayMs) {
|
|
30005
|
+
return new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
30006
|
+
}
|
|
30007
|
+
function readLockState(lockPath) {
|
|
30008
|
+
try {
|
|
30009
|
+
const stat2 = fs10.lstatSync(lockPath);
|
|
30010
|
+
if (!stat2.isFile() || stat2.isSymbolicLink() || stat2.size > 4096) {
|
|
30011
|
+
return { modifiedAt: stat2.mtimeMs, owner: null };
|
|
30012
|
+
}
|
|
30013
|
+
try {
|
|
30014
|
+
const value = JSON.parse(fs10.readFileSync(lockPath, "utf8"));
|
|
30015
|
+
const owner = Number.isInteger(value.pid) && value.pid > 0 && typeof value.startedAt === "number" && Number.isFinite(value.startedAt) && value.startedAt > 0 ? { pid: value.pid, startedAt: value.startedAt } : null;
|
|
30016
|
+
return { modifiedAt: stat2.mtimeMs, owner };
|
|
30017
|
+
} catch {
|
|
30018
|
+
return { modifiedAt: stat2.mtimeMs, owner: null };
|
|
30019
|
+
}
|
|
30020
|
+
} catch {
|
|
30021
|
+
return null;
|
|
30022
|
+
}
|
|
30023
|
+
}
|
|
30024
|
+
async function withNativeHostUpdateLock(lockPath, targetVersion, operation) {
|
|
30025
|
+
fs10.mkdirSync(path11.dirname(lockPath), { recursive: true, mode: 448 });
|
|
30026
|
+
const startedAt = Date.now();
|
|
30027
|
+
const owner = `${JSON.stringify({ pid: process.pid, startedAt, targetVersion })}
|
|
30028
|
+
`;
|
|
30029
|
+
while (true) {
|
|
30030
|
+
try {
|
|
30031
|
+
const handle = fs10.openSync(lockPath, "wx", 384);
|
|
30032
|
+
try {
|
|
30033
|
+
fs10.writeFileSync(handle, owner, "utf8");
|
|
30034
|
+
} finally {
|
|
30035
|
+
fs10.closeSync(handle);
|
|
30036
|
+
}
|
|
30037
|
+
break;
|
|
30038
|
+
} catch (error48) {
|
|
30039
|
+
if (!(error48 instanceof Error) || !("code" in error48) || error48.code !== "EEXIST") throw error48;
|
|
30040
|
+
const existing = readLockState(lockPath);
|
|
30041
|
+
const staleAfter = existing?.owner ? NATIVE_HOST_UPDATE_TIMEOUT_MS : INVALID_UPDATE_LOCK_GRACE_MS;
|
|
30042
|
+
const referenceTime = existing?.owner?.startedAt ?? existing?.modifiedAt;
|
|
30043
|
+
const expired = referenceTime !== void 0 && Date.now() - referenceTime > staleAfter;
|
|
30044
|
+
const ownerAlive = existing?.owner ? isAlive(existing.owner.pid) : false;
|
|
30045
|
+
if (expired && !ownerAlive) {
|
|
30046
|
+
try {
|
|
30047
|
+
fs10.unlinkSync(lockPath);
|
|
30048
|
+
continue;
|
|
30049
|
+
} catch {
|
|
30050
|
+
}
|
|
30051
|
+
}
|
|
30052
|
+
if (Date.now() - startedAt > NATIVE_HOST_UPDATE_TIMEOUT_MS + 1e4) {
|
|
30053
|
+
throw new NativeHostUpdateFailure(
|
|
30054
|
+
"lock-timeout",
|
|
30055
|
+
"Another Mearl Native Host update did not finish in time"
|
|
30056
|
+
);
|
|
30057
|
+
}
|
|
30058
|
+
await wait(UPDATE_LOCK_POLL_MS);
|
|
30059
|
+
}
|
|
30060
|
+
}
|
|
30061
|
+
try {
|
|
30062
|
+
return await operation();
|
|
30063
|
+
} finally {
|
|
30064
|
+
try {
|
|
30065
|
+
if (fs10.readFileSync(lockPath, "utf8") === owner) fs10.unlinkSync(lockPath);
|
|
30066
|
+
} catch {
|
|
30067
|
+
}
|
|
30068
|
+
}
|
|
30069
|
+
}
|
|
30070
|
+
function classifyUpdateFailure(output) {
|
|
30071
|
+
if (/\b(?:E404|ETARGET)\b|no matching version found|404\s+not found|package.+not found/i.test(
|
|
30072
|
+
output
|
|
30073
|
+
)) {
|
|
30074
|
+
return "package-unavailable";
|
|
30075
|
+
}
|
|
30076
|
+
if (/\b(?:EAI_AGAIN|ECONNREFUSED|ECONNRESET|ENETUNREACH|ENOTFOUND|ERR_SOCKET_TIMEOUT)\b|fetch failed|network request/i.test(
|
|
30077
|
+
output
|
|
30078
|
+
)) {
|
|
30079
|
+
return "network";
|
|
30080
|
+
}
|
|
30081
|
+
return "setup-failed";
|
|
30082
|
+
}
|
|
30083
|
+
function nativeHostUpdateCommand(targetVersion) {
|
|
30084
|
+
if (!isMearlReleaseVersion(targetVersion)) {
|
|
30085
|
+
throw new Error("The Native Host update target must be a valid Mearl release");
|
|
30086
|
+
}
|
|
30087
|
+
const releaseLine = mearlReleaseLineForVersion(targetVersion);
|
|
30088
|
+
const packageSpec = `@mearl/setup@${releaseLine}`;
|
|
30089
|
+
const args = [
|
|
30090
|
+
"--yes",
|
|
30091
|
+
packageSpec,
|
|
30092
|
+
"update",
|
|
30093
|
+
"--local",
|
|
30094
|
+
"--yes",
|
|
30095
|
+
"--target-line",
|
|
30096
|
+
releaseLine,
|
|
30097
|
+
"--skip-skill"
|
|
30098
|
+
];
|
|
30099
|
+
return {
|
|
30100
|
+
args
|
|
30101
|
+
};
|
|
30102
|
+
}
|
|
30103
|
+
function currentNativeHostPackageRoot(entryPath) {
|
|
30104
|
+
let current = path11.dirname(entryPath);
|
|
30105
|
+
for (let depth = 0; depth < 12; depth += 1) {
|
|
30106
|
+
try {
|
|
30107
|
+
const manifest = JSON.parse(fs10.readFileSync(path11.join(current, "package.json"), "utf8"));
|
|
30108
|
+
if (manifest.name === "@mearl/native-host") return current;
|
|
30109
|
+
} catch {
|
|
30110
|
+
}
|
|
30111
|
+
const parent = path11.dirname(current);
|
|
30112
|
+
if (parent === current) break;
|
|
30113
|
+
current = parent;
|
|
30114
|
+
}
|
|
30115
|
+
return null;
|
|
30116
|
+
}
|
|
30117
|
+
function currentPackageManagerInstallation(environment, nodePath, platform) {
|
|
30118
|
+
const packageRoot = currentNativeHostPackageRoot(fileURLToPath(import.meta.url));
|
|
30119
|
+
if (!packageRoot) return null;
|
|
30120
|
+
return resolvePackageManagerInstallation(packageRoot, "@mearl/native-host", {
|
|
30121
|
+
env: environment,
|
|
30122
|
+
platform,
|
|
30123
|
+
processExecPath: nodePath
|
|
30124
|
+
});
|
|
30125
|
+
}
|
|
30126
|
+
async function installedLocalPackagesMatch(targetReleaseLine, environment, runner) {
|
|
30127
|
+
const installedVersions = [];
|
|
30128
|
+
for (const executableName of ["mearl-native-host", "mearl"]) {
|
|
30129
|
+
const executable = findExecutable(executableName, { env: environment });
|
|
30130
|
+
if (!executable) return false;
|
|
30131
|
+
try {
|
|
30132
|
+
const result = await runner(executable, ["--version"], {
|
|
30133
|
+
capture: true,
|
|
30134
|
+
env: environment,
|
|
30135
|
+
timeoutMs: 5e3
|
|
30136
|
+
});
|
|
30137
|
+
const installedVersion = result.stdout.trim();
|
|
30138
|
+
if (result.code !== 0 || !isMearlReleaseVersionInLine(installedVersion, targetReleaseLine)) {
|
|
30139
|
+
return false;
|
|
30140
|
+
}
|
|
30141
|
+
installedVersions.push(installedVersion);
|
|
30142
|
+
} catch {
|
|
30143
|
+
return false;
|
|
30144
|
+
}
|
|
30145
|
+
}
|
|
30146
|
+
return new Set(installedVersions).size === 1;
|
|
30147
|
+
}
|
|
30148
|
+
async function runNativeHostUpdate(targetVersion, options = {}) {
|
|
30149
|
+
const command = nativeHostUpdateCommand(targetVersion);
|
|
30150
|
+
const targetReleaseLine = mearlReleaseLineForVersion(targetVersion);
|
|
30151
|
+
const environment = options.environment ?? process.env;
|
|
30152
|
+
const platform = options.platform ?? process.platform;
|
|
30153
|
+
const nodePath = options.nodePath ?? process.execPath;
|
|
30154
|
+
const currentInstallation = currentPackageManagerInstallation(environment, nodePath, platform);
|
|
30155
|
+
const managerCommand = options.packageManagerCommand === void 0 ? currentInstallation?.command ?? null : options.packageManagerCommand;
|
|
30156
|
+
const packageBinDirectory = options.packageBinDirectory === void 0 ? currentInstallation?.binDirectory ?? null : options.packageBinDirectory;
|
|
30157
|
+
let childEnvironment = prependNodePath(environment, nodePath);
|
|
30158
|
+
if (managerCommand) childEnvironment = prependCommandPath(managerCommand, childEnvironment);
|
|
30159
|
+
if (packageBinDirectory) {
|
|
30160
|
+
childEnvironment = prependPathDirectory(packageBinDirectory, childEnvironment);
|
|
30161
|
+
}
|
|
30162
|
+
const packageRunner = options.packageRunner ?? findExecutable("npx", {
|
|
30163
|
+
env: childEnvironment,
|
|
30164
|
+
extraDirectories: [path11.dirname(nodePath)],
|
|
30165
|
+
platform
|
|
30166
|
+
});
|
|
30167
|
+
if (!packageRunner) {
|
|
30168
|
+
throw new NativeHostUpdateFailure("package-unavailable", "The package runner is unavailable");
|
|
30169
|
+
}
|
|
30170
|
+
const runner = options.runner ?? runCommand;
|
|
30171
|
+
const areTargetsInstalled = options.areTargetsInstalled ?? ((version2, env) => installedLocalPackagesMatch(version2, env, runner));
|
|
30172
|
+
const withUpdateLock = options.withUpdateLock ?? ((version2, operation) => withNativeHostUpdateLock(options.updateLockPath ?? UPDATE_LOCK_PATH, version2, operation));
|
|
30173
|
+
await withUpdateLock(targetVersion, async () => {
|
|
30174
|
+
let result;
|
|
30175
|
+
try {
|
|
30176
|
+
result = await runner(packageRunner, command.args, {
|
|
30177
|
+
capture: true,
|
|
30178
|
+
env: childEnvironment,
|
|
30179
|
+
timeoutMs: options.timeoutMs ?? NATIVE_HOST_UPDATE_TIMEOUT_MS
|
|
30180
|
+
});
|
|
30181
|
+
} catch (error48) {
|
|
30182
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
30183
|
+
const classified = classifyUpdateFailure(message);
|
|
30184
|
+
throw new NativeHostUpdateFailure(
|
|
30185
|
+
/timed out/i.test(message) ? "timeout" : classified === "setup-failed" ? "unknown" : classified,
|
|
30186
|
+
"The Native Host update process did not complete"
|
|
30187
|
+
);
|
|
30188
|
+
}
|
|
30189
|
+
if (result.code !== 0) {
|
|
30190
|
+
throw new NativeHostUpdateFailure(
|
|
30191
|
+
classifyUpdateFailure(`${result.stderr.slice(0, 8192)}
|
|
30192
|
+
${result.stdout.slice(0, 8192)}`),
|
|
30193
|
+
"The Mearl setup release line did not complete successfully"
|
|
30194
|
+
);
|
|
30195
|
+
}
|
|
30196
|
+
if (!await areTargetsInstalled(targetReleaseLine, childEnvironment)) {
|
|
30197
|
+
throw new NativeHostUpdateFailure(
|
|
30198
|
+
"verification-failed",
|
|
30199
|
+
"The installed Native Host and client do not match the Extension release line"
|
|
30200
|
+
);
|
|
30201
|
+
}
|
|
30202
|
+
});
|
|
30203
|
+
}
|
|
30204
|
+
var NativeHostUpdateCoordinator = class {
|
|
30205
|
+
constructor(options) {
|
|
30206
|
+
this.options = options;
|
|
30207
|
+
}
|
|
30208
|
+
#automaticAttempted = false;
|
|
30209
|
+
#operation = null;
|
|
30210
|
+
evaluate(extensionVersion2, checkForUpdates) {
|
|
30211
|
+
if (checkForUpdates !== true || this.#automaticAttempted || this.#operation) return;
|
|
30212
|
+
if (!isMearlReleaseVersion(extensionVersion2) || !isMearlReleaseVersion(this.options.hostVersion)) {
|
|
30213
|
+
this.options.log("Skipped Native Host update check because a release version was invalid");
|
|
30214
|
+
return;
|
|
30215
|
+
}
|
|
30216
|
+
const targetVersion = extensionVersion2;
|
|
30217
|
+
if (compareMearlReleaseLines(this.options.hostVersion, targetVersion) >= 0) return;
|
|
30218
|
+
this.#automaticAttempted = true;
|
|
30219
|
+
const operation = this.options.runUpdate(targetVersion).then(() => this.options.requestRestart()).catch((error48) => {
|
|
30220
|
+
const category = error48 instanceof NativeHostUpdateFailure ? error48.updateError : "unknown";
|
|
30221
|
+
this.options.log(`Native Host automatic update failed (${category})`);
|
|
30222
|
+
}).finally(() => {
|
|
30223
|
+
if (this.#operation === operation) this.#operation = null;
|
|
30224
|
+
});
|
|
30225
|
+
this.#operation = operation;
|
|
30226
|
+
}
|
|
30227
|
+
};
|
|
30228
|
+
|
|
29393
30229
|
// src/index.ts
|
|
29394
30230
|
var cliArgs = process.argv.slice(2);
|
|
29395
30231
|
var cliArg = cliArgs[0];
|
|
@@ -29456,11 +30292,11 @@ Examples:
|
|
|
29456
30292
|
process.exit(0);
|
|
29457
30293
|
}
|
|
29458
30294
|
function socketPathFor(suffix) {
|
|
29459
|
-
return process.platform === "win32" ? `\\\\.\\pipe\\mearl-agent${suffix}` :
|
|
30295
|
+
return process.platform === "win32" ? `\\\\.\\pipe\\mearl-agent${suffix}` : path14.join(os7.tmpdir(), `mearl-agent${suffix}.sock`);
|
|
29460
30296
|
}
|
|
29461
30297
|
var LEGACY_SOCKET_PATH = socketPathFor("");
|
|
29462
30298
|
var INSTANCE_SOCKET_PATH = socketPathFor(`-${process.pid}`);
|
|
29463
|
-
var LOG_FILE =
|
|
30299
|
+
var LOG_FILE = path14.join(os7.tmpdir(), "mearl-native-host.log");
|
|
29464
30300
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
29465
30301
|
var INVENTORY_IDLE_EXIT_MS = 1e3;
|
|
29466
30302
|
var MAX_SOCKET_BUFFER_SIZE = 64 * 1024 * 1024;
|
|
@@ -29559,7 +30395,7 @@ function log(...args) {
|
|
|
29559
30395
|
const msg = `[${(/* @__PURE__ */ new Date()).toISOString()}] [NativeHost] ${args.join(" ")}
|
|
29560
30396
|
`;
|
|
29561
30397
|
try {
|
|
29562
|
-
|
|
30398
|
+
fs13.appendFileSync(LOG_FILE, msg);
|
|
29563
30399
|
} catch {
|
|
29564
30400
|
}
|
|
29565
30401
|
}
|
|
@@ -29571,6 +30407,14 @@ function sendToExtension(message) {
|
|
|
29571
30407
|
process.stdout.write(header);
|
|
29572
30408
|
process.stdout.write(json2);
|
|
29573
30409
|
}
|
|
30410
|
+
var nativeHostUpdateCoordinator = new NativeHostUpdateCoordinator({
|
|
30411
|
+
hostVersion: NATIVE_HOST_VERSION,
|
|
30412
|
+
log,
|
|
30413
|
+
runUpdate: (targetVersion) => runNativeHostUpdate(targetVersion),
|
|
30414
|
+
requestRestart: () => {
|
|
30415
|
+
restartAfterUpdate();
|
|
30416
|
+
}
|
|
30417
|
+
});
|
|
29574
30418
|
var agentChatManager = null;
|
|
29575
30419
|
var agentSkillManager = new AgentSkillManager();
|
|
29576
30420
|
function getAgentChatManager() {
|
|
@@ -29681,6 +30525,7 @@ function handleExtensionMessage(message) {
|
|
|
29681
30525
|
extensionVersion: extensionVersion ?? void 0
|
|
29682
30526
|
});
|
|
29683
30527
|
sendToExtension({ type: "pong", timestamp: Date.now(), version: NATIVE_HOST_VERSION });
|
|
30528
|
+
nativeHostUpdateCoordinator.evaluate(message.version, message.checkForUpdates);
|
|
29684
30529
|
return;
|
|
29685
30530
|
}
|
|
29686
30531
|
if (message && message.type === "browser_focus") {
|
|
@@ -29964,7 +30809,7 @@ async function handleSocketLine(socket, line) {
|
|
|
29964
30809
|
return result2.cookies ?? [];
|
|
29965
30810
|
} : (domains) => cdpExportCookies(getCdpSession(), domains);
|
|
29966
30811
|
const result = await launchManagedBrowser(data, {
|
|
29967
|
-
nativeHostScript:
|
|
30812
|
+
nativeHostScript: fileURLToPath3(import.meta.url),
|
|
29968
30813
|
prepareTdbankSso,
|
|
29969
30814
|
exportCookies,
|
|
29970
30815
|
log
|
|
@@ -30093,7 +30938,7 @@ function onSocketConnection(socket) {
|
|
|
30093
30938
|
}
|
|
30094
30939
|
function isPathAlive(socketPath) {
|
|
30095
30940
|
return new Promise((resolve) => {
|
|
30096
|
-
if (process.platform !== "win32" && !
|
|
30941
|
+
if (process.platform !== "win32" && !fs13.existsSync(socketPath)) {
|
|
30097
30942
|
resolve(false);
|
|
30098
30943
|
return;
|
|
30099
30944
|
}
|
|
@@ -30116,9 +30961,9 @@ function isPathAlive(socketPath) {
|
|
|
30116
30961
|
}
|
|
30117
30962
|
function listenOn(socketPath) {
|
|
30118
30963
|
return new Promise((resolve, reject) => {
|
|
30119
|
-
if (process.platform !== "win32" &&
|
|
30964
|
+
if (process.platform !== "win32" && fs13.existsSync(socketPath)) {
|
|
30120
30965
|
try {
|
|
30121
|
-
|
|
30966
|
+
fs13.unlinkSync(socketPath);
|
|
30122
30967
|
} catch {
|
|
30123
30968
|
}
|
|
30124
30969
|
}
|
|
@@ -30127,11 +30972,11 @@ function listenOn(socketPath) {
|
|
|
30127
30972
|
server.listen(socketPath, () => {
|
|
30128
30973
|
if (process.platform !== "win32") {
|
|
30129
30974
|
try {
|
|
30130
|
-
|
|
30975
|
+
fs13.chmodSync(socketPath, 384);
|
|
30131
30976
|
} catch (error48) {
|
|
30132
30977
|
server.close();
|
|
30133
30978
|
try {
|
|
30134
|
-
|
|
30979
|
+
fs13.unlinkSync(socketPath);
|
|
30135
30980
|
} catch {
|
|
30136
30981
|
}
|
|
30137
30982
|
reject(error48);
|
|
@@ -30167,7 +31012,7 @@ function releaseLegacySocket() {
|
|
|
30167
31012
|
}
|
|
30168
31013
|
if (process.platform !== "win32") {
|
|
30169
31014
|
try {
|
|
30170
|
-
if (
|
|
31015
|
+
if (fs13.existsSync(LEGACY_SOCKET_PATH)) fs13.unlinkSync(LEGACY_SOCKET_PATH);
|
|
30171
31016
|
} catch {
|
|
30172
31017
|
}
|
|
30173
31018
|
}
|
|
@@ -30179,8 +31024,8 @@ async function startSocketServer() {
|
|
|
30179
31024
|
function cleanupInstanceSocketFile() {
|
|
30180
31025
|
if (process.platform === "win32") return;
|
|
30181
31026
|
try {
|
|
30182
|
-
if (
|
|
30183
|
-
|
|
31027
|
+
if (fs13.existsSync(INSTANCE_SOCKET_PATH)) {
|
|
31028
|
+
fs13.unlinkSync(INSTANCE_SOCKET_PATH);
|
|
30184
31029
|
}
|
|
30185
31030
|
} catch (error48) {
|
|
30186
31031
|
log("cleanup socket file failed:", String(error48));
|
|
@@ -30207,6 +31052,11 @@ function cleanupAndExit(code) {
|
|
|
30207
31052
|
}
|
|
30208
31053
|
finish();
|
|
30209
31054
|
}
|
|
31055
|
+
function restartAfterUpdate() {
|
|
31056
|
+
const forcedExit = setTimeout(() => process.exit(0), 2e3);
|
|
31057
|
+
forcedExit.unref();
|
|
31058
|
+
cleanupAndExit(0);
|
|
31059
|
+
}
|
|
30210
31060
|
async function main() {
|
|
30211
31061
|
initBrowserRegistry({ log });
|
|
30212
31062
|
pruneDeadBrowsers();
|