@cmmd-center/forge 0.13.28 → 0.13.30
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/{BunHttpServer-C0oPP_3A.cjs → BunHttpServer-CXndtc1j.cjs} +2 -2
- package/dist/{BunHttpServer-FbbQmsl_.mjs → BunHttpServer-DjilmGOM.mjs} +2 -2
- package/dist/{BunPTY-uyreNRGp.cjs → BunPTY-BiTlUj63.cjs} +1 -1
- package/dist/{BunPTY-DkAIzLIx.mjs → BunPTY-Csgwhbi5.mjs} +1 -1
- package/dist/{BunServices-DC7nhA3w.mjs → BunServices-BZKzHdrG.mjs} +1 -1
- package/dist/{BunServices-DkenwD7S.cjs → BunServices-DsWG7VM1.cjs} +1 -1
- package/dist/{NodeHttpServer-Cjd3bFrD.cjs → NodeHttpServer-B4dCKqYY.cjs} +1 -1
- package/dist/{NodeHttpServer-BJ4l15f-.mjs → NodeHttpServer-Ds3Gp1Gp.mjs} +1 -1
- package/dist/{NodePTY-BehazUMi.cjs → NodePTY-BJ7874MO.cjs} +1 -1
- package/dist/{NodePTY-BhezYy9H.mjs → NodePTY-DgXWLtWp.mjs} +1 -1
- package/dist/{NodeSqliteClient-CfsdC3AB.cjs → NodeSqliteClient-CPsJxxdD.cjs} +1 -1
- package/dist/{NodeSqliteClient-md8xd9hY.mjs → NodeSqliteClient-D29w60zZ.mjs} +1 -1
- package/dist/{SqliteClient-BKB695RF.mjs → SqliteClient-Bgo_s5sA.mjs} +1 -1
- package/dist/{SqliteClient-O1ABIngw.cjs → SqliteClient-k0pbfeIC.cjs} +1 -1
- package/dist/bin.cjs +432 -1012
- package/dist/bin.mjs +452 -1031
- package/dist/client/assets/{DiffPanel-CmdI2N7U.js → DiffPanel-u3cympMJ.js} +2 -2
- package/dist/client/assets/{DiffPanel.logic-DtFJMr9U.js → DiffPanel.logic-Im6HMxhw.js} +2 -2
- package/dist/client/assets/{DiffPanelShell-DStZuS4s.js → DiffPanelShell-BckZpJGo.js} +102 -102
- package/dist/client/assets/{DiffWorkerPoolProvider-CG8qkZ21.js → DiffWorkerPoolProvider-Bwjf7Bmf.js} +2 -2
- package/dist/client/assets/{PullRequestCodePanel-pc6WtcMu.js → PullRequestCodePanel-VADCfzOQ.js} +2 -2
- package/dist/client/assets/{Virtualizer-DQWCMRz2.js → Virtualizer-Dp4FFzsC.js} +2 -2
- package/dist/client/assets/{index-AZc0SrFH.js → index-CiD_w5sq.js} +7 -7
- package/dist/client/index.html +4 -4
- package/dist/{execAsync-BUcaFQ1D.cjs → execAsync--H9ZZOiC.cjs} +1 -1
- package/dist/{execAsync-BNNdR88o.mjs → execAsync-BJ4g1UuR.mjs} +1 -1
- package/dist/forge-build.json +1 -1
- package/dist/{getMachineId-bsd-3FzKrfVS.cjs → getMachineId-bsd-CJJWgsvW.cjs} +2 -2
- package/dist/{getMachineId-bsd-BuYwT36r.mjs → getMachineId-bsd-CvzjzhCJ.mjs} +2 -2
- package/dist/{getMachineId-darwin-RZKhGQ6C.mjs → getMachineId-darwin-BkjZ6NK7.mjs} +2 -2
- package/dist/{getMachineId-darwin-J2wNbebX.cjs → getMachineId-darwin-hZeIAq-t.cjs} +2 -2
- package/dist/{getMachineId-linux-BDLTrARB.cjs → getMachineId-linux-B4Pn5gp9.cjs} +1 -1
- package/dist/{getMachineId-linux-D5HSP0rH.mjs → getMachineId-linux-BaBxzaf3.mjs} +1 -1
- package/dist/{getMachineId-unsupported-DRh5MFwr.cjs → getMachineId-unsupported-B3jtoOL0.cjs} +1 -1
- package/dist/{getMachineId-unsupported-IaplPZnC.mjs → getMachineId-unsupported-EhCzrOph.mjs} +1 -1
- package/dist/{getMachineId-win-D220ursp.mjs → getMachineId-win-BFwtIsaZ.mjs} +2 -2
- package/dist/{getMachineId-win-BA8dHcjg.cjs → getMachineId-win-Bb4lJE8e.cjs} +2 -2
- package/dist/{open-FIgTDosf.mjs → open-2-reBrpv.mjs} +3 -3
- package/dist/{open-BAsPVCWX.cjs → open-CghsF25U.cjs} +1 -1
- package/dist/playwright-backend-BONxTCSA.cjs +643 -0
- package/dist/playwright-backend-DVQOhqRO.mjs +642 -0
- package/dist/settle-B6Rn65UV.cjs +28 -0
- package/dist/settle-BJcmpbvq.mjs +23 -0
- package/package.json +1 -1
package/dist/bin.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import { r as wrapper_default, t as Mime_default } from "./Mime-Dq9IoNiV.mjs";
|
|
|
13
13
|
import { a as diag, c as SpanKind$1, d as TraceFlags, f as ROOT_CONTEXT, i as propagation, l as isSpanContextValid, m as DiagLogLevel, n as init_esm$1, o as context$1, p as createContextKey, r as trace, s as SpanStatusCode, t as esm_exports$1 } from "./esm-wLIF-u3N.mjs";
|
|
14
14
|
import { a as verifyCmmdAuthRuntimeTicket, c as verifyCmmdRuntimeTicket, d as runtimeGrantToken, f as setRuntimeGrantToken, i as sendRuntimeControlHeartbeat, l as verifyCmmdRuntimeTicketRefreshProof, n as bootstrapRuntimeControlAuthorityFromNarrowGrant, o as verifyCmmdClaudeReadinessTicket, p as createReadOnceFileTokenAccessor, r as readRuntimeControlAuthority, s as verifyCmmdClaudeUsageTicket, t as bootstrapRuntimeControlAuthority, u as verifyCmmdScopedRuntimePayload } from "./runtimeControlAuthority-DpRIoWqP.mjs";
|
|
15
15
|
import { n as PtySpawnError, t as PtyAdapter } from "./PTY-BzdbZ0Ym.mjs";
|
|
16
|
+
import { t as settleValueWithin } from "./settle-BJcmpbvq.mjs";
|
|
16
17
|
import { createRequire } from "node:module";
|
|
17
18
|
import * as HE from "node:child_process";
|
|
18
19
|
import { execFile, execFileSync, spawn, spawnSync } from "node:child_process";
|
|
@@ -22,7 +23,7 @@ import { createCipheriv, createDecipheriv, createHash, createHmac, createPublicK
|
|
|
22
23
|
import * as FS$1 from "node:fs";
|
|
23
24
|
import fs, { accessSync, chmodSync, constants, createReadStream, existsSync, mkdirSync, mkdtempSync, promises, readFile, readFileSync, readdir, readdirSync, realpathSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
24
25
|
import * as NodeOS from "node:os";
|
|
25
|
-
import
|
|
26
|
+
import $U, { homedir, networkInterfaces, tmpdir } from "node:os";
|
|
26
27
|
import * as Path$1 from "node:path";
|
|
27
28
|
import path, { basename, delimiter, dirname, extname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
28
29
|
import { pathToFileURL } from "node:url";
|
|
@@ -73,7 +74,6 @@ import z$ from "http2";
|
|
|
73
74
|
import { access, appendFile, chmod as chmod$1, copyFile, link as link$1, lstat as lstat$1, mkdir as mkdir$1, open, readFile as readFile$2, readdir as readdir$2, readlink, realpath as realpath$1, rename as rename$1, rm as rm$1, rmdir, stat as stat$1, symlink, unlink as unlink$1, writeFile as writeFile$1 } from "fs/promises";
|
|
74
75
|
import { createInterface as createInterface$1 } from "readline";
|
|
75
76
|
import { AsyncLocalStorage as AsyncLocalStorage$1 } from "async_hooks";
|
|
76
|
-
import { chromium } from "playwright";
|
|
77
77
|
import { createSocket } from "node:dgram";
|
|
78
78
|
import { createSocket as createSocket$1 } from "dgram";
|
|
79
79
|
import { setTimeout as setTimeout$1 } from "timers/promises";
|
|
@@ -50549,7 +50549,7 @@ function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
|
50549
50549
|
const min = forceColor || 0;
|
|
50550
50550
|
if (env.TERM === "dumb") return min;
|
|
50551
50551
|
if (process$1.platform === "win32") {
|
|
50552
|
-
const osRelease =
|
|
50552
|
+
const osRelease = $U.release().split(".");
|
|
50553
50553
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
50554
50554
|
return 1;
|
|
50555
50555
|
}
|
|
@@ -52897,19 +52897,19 @@ var require_getMachineId = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52897
52897
|
async function getMachineId() {
|
|
52898
52898
|
if (!getMachineIdImpl) switch (process$3.platform) {
|
|
52899
52899
|
case "darwin":
|
|
52900
|
-
getMachineIdImpl = (await import("./getMachineId-darwin-
|
|
52900
|
+
getMachineIdImpl = (await import("./getMachineId-darwin-BkjZ6NK7.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
|
|
52901
52901
|
break;
|
|
52902
52902
|
case "linux":
|
|
52903
|
-
getMachineIdImpl = (await import("./getMachineId-linux-
|
|
52903
|
+
getMachineIdImpl = (await import("./getMachineId-linux-BaBxzaf3.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
|
|
52904
52904
|
break;
|
|
52905
52905
|
case "freebsd":
|
|
52906
|
-
getMachineIdImpl = (await import("./getMachineId-bsd-
|
|
52906
|
+
getMachineIdImpl = (await import("./getMachineId-bsd-CvzjzhCJ.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
|
|
52907
52907
|
break;
|
|
52908
52908
|
case "win32":
|
|
52909
|
-
getMachineIdImpl = (await import("./getMachineId-win-
|
|
52909
|
+
getMachineIdImpl = (await import("./getMachineId-win-BFwtIsaZ.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
|
|
52910
52910
|
break;
|
|
52911
52911
|
default:
|
|
52912
|
-
getMachineIdImpl = (await import("./getMachineId-unsupported-
|
|
52912
|
+
getMachineIdImpl = (await import("./getMachineId-unsupported-EhCzrOph.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
|
|
52913
52913
|
break;
|
|
52914
52914
|
}
|
|
52915
52915
|
return getMachineIdImpl();
|
|
@@ -52992,7 +52992,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
52992
52992
|
exports.processDetector = void 0;
|
|
52993
52993
|
const api_1 = (init_esm$1(), __toCommonJS(esm_exports$1));
|
|
52994
52994
|
const semconv_1 = require_semconv$1();
|
|
52995
|
-
const os$
|
|
52995
|
+
const os$3 = __require("os");
|
|
52996
52996
|
/**
|
|
52997
52997
|
* ProcessDetector will be used to detect the resources related current process running
|
|
52998
52998
|
* and being instrumented from the NodeJS Process module.
|
|
@@ -53014,7 +53014,7 @@ var require_ProcessDetector = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
53014
53014
|
};
|
|
53015
53015
|
if (process.argv.length > 1) attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
|
|
53016
53016
|
try {
|
|
53017
|
-
const userInfo = os$
|
|
53017
|
+
const userInfo = os$3.userInfo();
|
|
53018
53018
|
attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
|
|
53019
53019
|
} catch (e) {
|
|
53020
53020
|
api_1.diag.debug(`error obtaining process owner: ${e}`);
|
|
@@ -65937,7 +65937,7 @@ function normalizeNumberish(value) {
|
|
|
65937
65937
|
}
|
|
65938
65938
|
//#endregion
|
|
65939
65939
|
//#region package.json
|
|
65940
|
-
var version$1 = "0.13.
|
|
65940
|
+
var version$1 = "0.13.30";
|
|
65941
65941
|
//#endregion
|
|
65942
65942
|
//#region src/sentry.ts
|
|
65943
65943
|
const SERVER_APP_NAME = "forge-server";
|
|
@@ -75819,7 +75819,7 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
75819
75819
|
var fs$6 = __require("fs");
|
|
75820
75820
|
var path$5 = __require("path");
|
|
75821
75821
|
var url$1 = __require("url");
|
|
75822
|
-
var os$
|
|
75822
|
+
var os$2 = __require("os");
|
|
75823
75823
|
var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
75824
75824
|
var vars = process.config && process.config.variables || {};
|
|
75825
75825
|
var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
|
|
@@ -75827,8 +75827,8 @@ var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
75827
75827
|
var abi = versions.modules;
|
|
75828
75828
|
if (versions.deno || process.isBun) abi = "unsupported";
|
|
75829
75829
|
var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
|
|
75830
|
-
var arch = process.env.npm_config_arch || os$
|
|
75831
|
-
var platform = process.env.npm_config_platform || os$
|
|
75830
|
+
var arch = process.env.npm_config_arch || os$2.arch();
|
|
75831
|
+
var platform = process.env.npm_config_platform || os$2.platform();
|
|
75832
75832
|
var libc = process.env.LIBC || (isMusl(platform) ? "musl" : "glibc");
|
|
75833
75833
|
var armv = process.env.ARM_VERSION || (arch === "arm64" ? "8" : vars.arm_version) || "";
|
|
75834
75834
|
var uv = (versions.uv || "").split(".")[0];
|
|
@@ -93516,7 +93516,7 @@ const launchDetached = (launch) => gen(function* () {
|
|
|
93516
93516
|
});
|
|
93517
93517
|
const OpenLive = effect(Open, gen(function* () {
|
|
93518
93518
|
const open = yield* tryPromise({
|
|
93519
|
-
try: () => import("./open-
|
|
93519
|
+
try: () => import("./open-2-reBrpv.mjs"),
|
|
93520
93520
|
catch: (cause) => new OpenError$1({
|
|
93521
93521
|
message: "failed to load browser opener",
|
|
93522
93522
|
cause
|
|
@@ -118053,8 +118053,8 @@ effectDiscard(runMigrations());
|
|
|
118053
118053
|
//#endregion
|
|
118054
118054
|
//#region src/persistence/Layers/Sqlite.ts
|
|
118055
118055
|
const defaultSqliteClientLoaders = {
|
|
118056
|
-
bun: () => import("./SqliteClient-
|
|
118057
|
-
node: () => import("./NodeSqliteClient-
|
|
118056
|
+
bun: () => import("./SqliteClient-Bgo_s5sA.mjs"),
|
|
118057
|
+
node: () => import("./NodeSqliteClient-D29w60zZ.mjs")
|
|
118058
118058
|
};
|
|
118059
118059
|
const makeRuntimeSqliteLayer = fn$1("makeRuntimeSqliteLayer")(function* (config) {
|
|
118060
118060
|
const loader = defaultSqliteClientLoaders[process.versions.bun !== void 0 ? "bun" : "node"];
|
|
@@ -190992,7 +190992,7 @@ var Vce = {
|
|
|
190992
190992
|
function Ve() {
|
|
190993
190993
|
return Vce;
|
|
190994
190994
|
}
|
|
190995
|
-
var Us =
|
|
190995
|
+
var Us = $U.homedir(), lk = $U.tmpdir(), { env: Vc } = process$1, Yce = (e) => {
|
|
190996
190996
|
let t = path.join(Us, "Library");
|
|
190997
190997
|
return {
|
|
190998
190998
|
data: path.join(t, "Application Support", e),
|
|
@@ -201192,12 +201192,12 @@ function qZ(e, t) {
|
|
|
201192
201192
|
}
|
|
201193
201193
|
return n;
|
|
201194
201194
|
}
|
|
201195
|
-
var os$
|
|
201195
|
+
var os$1 = "https://code.claude.com/docs/en", kKe = [
|
|
201196
201196
|
{
|
|
201197
201197
|
matches: (e) => e.path === "permissions.defaultMode" && e.code === "invalid_value",
|
|
201198
201198
|
tip: {
|
|
201199
201199
|
suggestion: "Valid modes: \"acceptEdits\" (ask before file changes), \"plan\" (analysis only), \"bypassPermissions\" (auto-accept all), or \"default\" (standard behavior)",
|
|
201200
|
-
docLink: `${os$
|
|
201200
|
+
docLink: `${os$1}/iam#permission-modes`
|
|
201201
201201
|
}
|
|
201202
201202
|
},
|
|
201203
201203
|
{
|
|
@@ -201212,7 +201212,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201212
201212
|
matches: (e) => e.path.startsWith("env.") && e.code === "invalid_type",
|
|
201213
201213
|
tip: {
|
|
201214
201214
|
suggestion: "Environment variables must be strings. Wrap numbers and booleans in quotes. Example: \"DEBUG\": \"true\", \"PORT\": \"3000\"",
|
|
201215
|
-
docLink: `${os$
|
|
201215
|
+
docLink: `${os$1}/settings#environment-variables`
|
|
201216
201216
|
}
|
|
201217
201217
|
},
|
|
201218
201218
|
{
|
|
@@ -201223,14 +201223,14 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201223
201223
|
matches: (e) => e.path.startsWith("hooks.") && e.code === "invalid_key",
|
|
201224
201224
|
tip: {
|
|
201225
201225
|
suggestion: "Not a recognized hook event. Common events: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, Stop. Check spelling and capitalization.",
|
|
201226
|
-
docLink: `${os$
|
|
201226
|
+
docLink: `${os$1}/hooks`
|
|
201227
201227
|
}
|
|
201228
201228
|
},
|
|
201229
201229
|
{
|
|
201230
201230
|
matches: (e) => /\.hooks\.\d+\.command$/.test(e.path) && e.code === "invalid_type" && e.received === "undefined",
|
|
201231
201231
|
tip: {
|
|
201232
201232
|
suggestion: "Command hooks require `command`. For exec form (no shell), set `command` to the executable and `args` to its arguments: {\"type\": \"command\", \"command\": \"echo\", \"args\": [\"hi\"]}. For shell form, set `command` to the full shell string: {\"type\": \"command\", \"command\": \"echo hi\"}.",
|
|
201233
|
-
docLink: `${os$
|
|
201233
|
+
docLink: `${os$1}/hooks#exec-form-and-shell-form`
|
|
201234
201234
|
}
|
|
201235
201235
|
},
|
|
201236
201236
|
{
|
|
@@ -201245,7 +201245,7 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201245
201245
|
matches: (e) => e.code === "unrecognized_keys",
|
|
201246
201246
|
tip: {
|
|
201247
201247
|
suggestion: "Check for typos or refer to the documentation for valid fields",
|
|
201248
|
-
docLink: `${os$
|
|
201248
|
+
docLink: `${os$1}/settings`
|
|
201249
201249
|
}
|
|
201250
201250
|
},
|
|
201251
201251
|
{
|
|
@@ -201260,13 +201260,13 @@ var os$2 = "https://code.claude.com/docs/en", kKe = [
|
|
|
201260
201260
|
matches: (e) => e.path === "permissions.additionalDirectories" && e.code === "invalid_type",
|
|
201261
201261
|
tip: {
|
|
201262
201262
|
suggestion: "Must be an array of directory paths. Example: [\"~/projects\", \"/tmp/workspace\"]. You can also use --add-dir flag or /add-dir command",
|
|
201263
|
-
docLink: `${os$
|
|
201263
|
+
docLink: `${os$1}/iam#working-directories`
|
|
201264
201264
|
}
|
|
201265
201265
|
}
|
|
201266
201266
|
], AKe = {
|
|
201267
|
-
permissions: `${os$
|
|
201268
|
-
env: `${os$
|
|
201269
|
-
hooks: `${os$
|
|
201267
|
+
permissions: `${os$1}/iam#configuring-permissions`,
|
|
201268
|
+
env: `${os$1}/settings#environment-variables`,
|
|
201269
|
+
hooks: `${os$1}/hooks`
|
|
201270
201270
|
};
|
|
201271
201271
|
function GZ(e) {
|
|
201272
201272
|
let t = kKe.find((r) => r.matches(e));
|
|
@@ -238689,24 +238689,6 @@ var BrowserActionEventRecorder = class {
|
|
|
238689
238689
|
}
|
|
238690
238690
|
};
|
|
238691
238691
|
//#endregion
|
|
238692
|
-
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/core/settle.js
|
|
238693
|
-
async function settleValueWithin(promise, timeoutMs) {
|
|
238694
|
-
let timer;
|
|
238695
|
-
try {
|
|
238696
|
-
return await Promise.race([promise.then((value) => ({
|
|
238697
|
-
status: "fulfilled",
|
|
238698
|
-
value
|
|
238699
|
-
}), (error) => ({
|
|
238700
|
-
error,
|
|
238701
|
-
status: "rejected"
|
|
238702
|
-
})), new Promise((resolve) => {
|
|
238703
|
-
timer = setTimeout(() => resolve({ status: "timed-out" }), timeoutMs);
|
|
238704
|
-
})]);
|
|
238705
|
-
} finally {
|
|
238706
|
-
clearTimeout(timer);
|
|
238707
|
-
}
|
|
238708
|
-
}
|
|
238709
|
-
//#endregion
|
|
238710
238692
|
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/safety/policy.js
|
|
238711
238693
|
var DefaultSafetyPolicy = class {
|
|
238712
238694
|
evaluate(action) {
|
|
@@ -238921,7 +238903,7 @@ var AgentBrowser = class {
|
|
|
238921
238903
|
async clickAction(action) {
|
|
238922
238904
|
await this.run({
|
|
238923
238905
|
kind: "click",
|
|
238924
|
-
selector: locatorActionLabel
|
|
238906
|
+
selector: locatorActionLabel(action)
|
|
238925
238907
|
}, async (tab) => {
|
|
238926
238908
|
await tab.click(action);
|
|
238927
238909
|
});
|
|
@@ -238933,7 +238915,7 @@ var AgentBrowser = class {
|
|
|
238933
238915
|
async doubleClickAction(action) {
|
|
238934
238916
|
await this.run({
|
|
238935
238917
|
kind: "click",
|
|
238936
|
-
selector: locatorActionLabel
|
|
238918
|
+
selector: locatorActionLabel(action)
|
|
238937
238919
|
}, async (tab) => {
|
|
238938
238920
|
await tab.doubleClick(action);
|
|
238939
238921
|
});
|
|
@@ -238945,7 +238927,7 @@ var AgentBrowser = class {
|
|
|
238945
238927
|
async fillAction(action, value) {
|
|
238946
238928
|
await this.run({
|
|
238947
238929
|
kind: "fill",
|
|
238948
|
-
selector: locatorActionLabel
|
|
238930
|
+
selector: locatorActionLabel(action),
|
|
238949
238931
|
value
|
|
238950
238932
|
}, async (tab) => {
|
|
238951
238933
|
await tab.fill(action, value);
|
|
@@ -238958,7 +238940,7 @@ var AgentBrowser = class {
|
|
|
238958
238940
|
async typeAction(action, value) {
|
|
238959
238941
|
await this.run({
|
|
238960
238942
|
kind: "fill",
|
|
238961
|
-
selector: locatorActionLabel
|
|
238943
|
+
selector: locatorActionLabel(action),
|
|
238962
238944
|
value
|
|
238963
238945
|
}, async (tab) => {
|
|
238964
238946
|
await tab.type(action, value);
|
|
@@ -238971,7 +238953,7 @@ var AgentBrowser = class {
|
|
|
238971
238953
|
async pressAction(action, key) {
|
|
238972
238954
|
await this.run({
|
|
238973
238955
|
kind: "press",
|
|
238974
|
-
selector: locatorActionLabel
|
|
238956
|
+
selector: locatorActionLabel(action),
|
|
238975
238957
|
key
|
|
238976
238958
|
}, async (tab) => {
|
|
238977
238959
|
await tab.press(action, key);
|
|
@@ -238984,7 +238966,7 @@ var AgentBrowser = class {
|
|
|
238984
238966
|
async selectAction(action, value) {
|
|
238985
238967
|
await this.run({
|
|
238986
238968
|
kind: "select",
|
|
238987
|
-
selector: locatorActionLabel
|
|
238969
|
+
selector: locatorActionLabel(action),
|
|
238988
238970
|
value
|
|
238989
238971
|
}, async (tab) => {
|
|
238990
238972
|
await tab.select(action, value);
|
|
@@ -238997,7 +238979,7 @@ var AgentBrowser = class {
|
|
|
238997
238979
|
async checkAction(action, checked) {
|
|
238998
238980
|
await this.run({
|
|
238999
238981
|
kind: "click",
|
|
239000
|
-
selector: locatorActionLabel
|
|
238982
|
+
selector: locatorActionLabel(action),
|
|
239001
238983
|
value: String(checked)
|
|
239002
238984
|
}, async (tab) => {
|
|
239003
238985
|
await tab.check(action, checked);
|
|
@@ -239233,7 +239215,7 @@ function locatorAction(selector, timeoutMs) {
|
|
|
239233
239215
|
timeoutMs
|
|
239234
239216
|
};
|
|
239235
239217
|
}
|
|
239236
|
-
function locatorActionLabel
|
|
239218
|
+
function locatorActionLabel(action) {
|
|
239237
239219
|
return action.selector ?? action.query?.kind ?? "locator";
|
|
239238
239220
|
}
|
|
239239
239221
|
//#endregion
|
|
@@ -240340,640 +240322,6 @@ function isPromiseLike(value) {
|
|
|
240340
240322
|
return !!value && typeof value.then === "function";
|
|
240341
240323
|
}
|
|
240342
240324
|
//#endregion
|
|
240343
|
-
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/backends/playwright-locators.js
|
|
240344
|
-
function locatorForAction(page, action) {
|
|
240345
|
-
return action.query ? locatorFromQuery(page, action.query) : page.locator(action.selector ?? "");
|
|
240346
|
-
}
|
|
240347
|
-
function locatorFromQuery(page, query) {
|
|
240348
|
-
switch (query.kind) {
|
|
240349
|
-
case "and": return locatorFromQuery(page, query.left).and(locatorFromQuery(page, query.right));
|
|
240350
|
-
case "css": return page.locator(query.selector);
|
|
240351
|
-
case "filter": return locatorFromQuery(page, query.base).filter(filterOptions(page, query.options));
|
|
240352
|
-
case "first": return locatorFromQuery(page, query.base).first();
|
|
240353
|
-
case "frame": return locatorInFrame(page, page.frameLocator(query.selector), query.child);
|
|
240354
|
-
case "label": return page.getByLabel(query.text, query.options);
|
|
240355
|
-
case "last": return locatorFromQuery(page, query.base).last();
|
|
240356
|
-
case "locator": return locatorFromQuery(page, query.base).locator(query.selector, filterOptions(page, query.options));
|
|
240357
|
-
case "nth": return locatorFromQuery(page, query.base).nth(query.index);
|
|
240358
|
-
case "or": return locatorFromQuery(page, query.left).or(locatorFromQuery(page, query.right));
|
|
240359
|
-
case "placeholder": return page.getByPlaceholder(query.text, query.options);
|
|
240360
|
-
case "role": return page.getByRole(query.role, query.options);
|
|
240361
|
-
case "testId": return page.getByTestId(query.testId);
|
|
240362
|
-
case "text": return page.getByText(query.text, query.options);
|
|
240363
|
-
}
|
|
240364
|
-
}
|
|
240365
|
-
function locatorInFrame(page, frame, query) {
|
|
240366
|
-
switch (query.kind) {
|
|
240367
|
-
case "css": return frame.locator(query.selector);
|
|
240368
|
-
case "filter": return locatorInFrame(page, frame, query.base).filter(filterOptions(page, query.options));
|
|
240369
|
-
case "first": return locatorInFrame(page, frame, query.base).first();
|
|
240370
|
-
case "label": return frame.getByLabel(query.text, query.options);
|
|
240371
|
-
case "last": return locatorInFrame(page, frame, query.base).last();
|
|
240372
|
-
case "locator": return locatorInFrame(page, frame, query.base).locator(query.selector, filterOptions(page, query.options));
|
|
240373
|
-
case "nth": return locatorInFrame(page, frame, query.base).nth(query.index);
|
|
240374
|
-
case "placeholder": return frame.getByPlaceholder(query.text, query.options);
|
|
240375
|
-
case "role": return frame.getByRole(query.role, query.options);
|
|
240376
|
-
case "testId": return frame.getByTestId(query.testId);
|
|
240377
|
-
case "text": return frame.getByText(query.text, query.options);
|
|
240378
|
-
case "and":
|
|
240379
|
-
case "frame":
|
|
240380
|
-
case "or": throw new Error(`Unsupported frame locator query kind: ${query.kind}`);
|
|
240381
|
-
}
|
|
240382
|
-
}
|
|
240383
|
-
function filterOptions(page, options) {
|
|
240384
|
-
if (!options) return void 0;
|
|
240385
|
-
return {
|
|
240386
|
-
...options.has === void 0 ? {} : { has: locatorFromQuery(page, options.has) },
|
|
240387
|
-
...options.hasNot === void 0 ? {} : { hasNot: locatorFromQuery(page, options.hasNot) },
|
|
240388
|
-
...options.hasNotText === void 0 ? {} : { hasNotText: options.hasNotText },
|
|
240389
|
-
...options.hasText === void 0 ? {} : { hasText: options.hasText }
|
|
240390
|
-
};
|
|
240391
|
-
}
|
|
240392
|
-
//#endregion
|
|
240393
|
-
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/backends/playwright-backend.js
|
|
240394
|
-
const TAB_METADATA_TIMEOUT_MS = 250;
|
|
240395
|
-
const TAB_CONTROL_TIMEOUT_MS = 500;
|
|
240396
|
-
var PlaywrightBackend = class {
|
|
240397
|
-
options;
|
|
240398
|
-
browser;
|
|
240399
|
-
context;
|
|
240400
|
-
pageIds = /* @__PURE__ */ new WeakMap();
|
|
240401
|
-
logs = /* @__PURE__ */ new WeakMap();
|
|
240402
|
-
registeredPages = /* @__PURE__ */ new WeakSet();
|
|
240403
|
-
constructor(options = {}) {
|
|
240404
|
-
this.options = options;
|
|
240405
|
-
}
|
|
240406
|
-
info() {
|
|
240407
|
-
return {
|
|
240408
|
-
id: "playwright",
|
|
240409
|
-
kind: "playwright",
|
|
240410
|
-
name: this.options.name ?? "Playwright Chromium"
|
|
240411
|
-
};
|
|
240412
|
-
}
|
|
240413
|
-
async close() {
|
|
240414
|
-
/* v8 ignore next -- defensive cleanup for already-closed Playwright contexts. */
|
|
240415
|
-
await this.context?.close().catch(() => void 0);
|
|
240416
|
-
await this.browser?.close();
|
|
240417
|
-
this.browser = void 0;
|
|
240418
|
-
this.context = void 0;
|
|
240419
|
-
}
|
|
240420
|
-
async listTabs() {
|
|
240421
|
-
const context = await this.getContext();
|
|
240422
|
-
return Promise.all(context.pages().map((page) => this.toTab(page).info()));
|
|
240423
|
-
}
|
|
240424
|
-
async selectedTab() {
|
|
240425
|
-
const page = (await this.getContext()).pages().at(-1);
|
|
240426
|
-
if (page) await settleValueWithin(page.bringToFront(), TAB_CONTROL_TIMEOUT_MS);
|
|
240427
|
-
return page ? this.toTab(page) : void 0;
|
|
240428
|
-
}
|
|
240429
|
-
async newTab() {
|
|
240430
|
-
const page = await (await this.getContext()).newPage();
|
|
240431
|
-
await this.preparePage(page);
|
|
240432
|
-
await settleValueWithin(page.bringToFront(), TAB_CONTROL_TIMEOUT_MS);
|
|
240433
|
-
return this.toTab(page);
|
|
240434
|
-
}
|
|
240435
|
-
async getTab(id) {
|
|
240436
|
-
const page = (await this.getContext()).pages().find((candidate) => this.idFor(candidate) === id);
|
|
240437
|
-
if (!page) throw new Error(`Tab not found: ${id}`);
|
|
240438
|
-
await settleValueWithin(page.bringToFront(), TAB_CONTROL_TIMEOUT_MS);
|
|
240439
|
-
return this.toTab(page);
|
|
240440
|
-
}
|
|
240441
|
-
async getContext() {
|
|
240442
|
-
/* v8 ignore next -- persistent headed/default launch combinations are covered by smoke, not unit coverage. */
|
|
240443
|
-
if (this.options.userDataDir && !this.context) {
|
|
240444
|
-
this.context = await chromium.launchPersistentContext(this.options.userDataDir, {
|
|
240445
|
-
...this.options.launchOptions,
|
|
240446
|
-
...this.options.contextOptions,
|
|
240447
|
-
headless: this.options.headless ?? false
|
|
240448
|
-
});
|
|
240449
|
-
this.browser = this.context.browser() ?? void 0;
|
|
240450
|
-
return this.context;
|
|
240451
|
-
}
|
|
240452
|
-
/* v8 ignore next -- requires a live externally managed Chrome CDP endpoint */
|
|
240453
|
-
if (!this.browser && this.options.cdpEndpoint) {
|
|
240454
|
-
/* v8 ignore start -- requires a live externally managed Chrome CDP endpoint */
|
|
240455
|
-
this.browser = await chromium.connectOverCDP(this.options.cdpEndpoint);
|
|
240456
|
-
this.context = this.browser.contexts()[0] ?? await this.browser.newContext(this.options.contextOptions);
|
|
240457
|
-
return this.context;
|
|
240458
|
-
}
|
|
240459
|
-
/* v8 ignore next -- headed/default launch is covered by browser parity smoke. */
|
|
240460
|
-
if (!this.browser) this.browser = await chromium.launch({
|
|
240461
|
-
...this.options.launchOptions,
|
|
240462
|
-
headless: this.options.headless ?? false
|
|
240463
|
-
});
|
|
240464
|
-
if (!this.context) this.context = await this.browser.newContext(this.options.contextOptions);
|
|
240465
|
-
return this.context;
|
|
240466
|
-
}
|
|
240467
|
-
toTab(page) {
|
|
240468
|
-
this.registerPage(page);
|
|
240469
|
-
return new PlaywrightTabHandle(page, this.idFor(page), this.logsFor(page));
|
|
240470
|
-
}
|
|
240471
|
-
async preparePage(page) {
|
|
240472
|
-
this.registerPage(page);
|
|
240473
|
-
const bounds = this.options.windowBounds;
|
|
240474
|
-
if (!bounds) return;
|
|
240475
|
-
await settleValueWithin(page.setViewportSize({
|
|
240476
|
-
width: bounds.width,
|
|
240477
|
-
height: bounds.height
|
|
240478
|
-
}), TAB_CONTROL_TIMEOUT_MS);
|
|
240479
|
-
const sessionResult = await settleValueWithin(page.context().newCDPSession(page), TAB_CONTROL_TIMEOUT_MS);
|
|
240480
|
-
/* v8 ignore next -- Playwright CDP attachment failures are bounded and covered by the shared timeout primitive. */
|
|
240481
|
-
if (sessionResult.status !== "fulfilled") return;
|
|
240482
|
-
const session = sessionResult.value;
|
|
240483
|
-
try {
|
|
240484
|
-
const windowResult = await settleValueWithin(session.send("Browser.getWindowForTarget"), TAB_CONTROL_TIMEOUT_MS);
|
|
240485
|
-
/* v8 ignore next -- Chromium may decline window control in unsupported headless/CDP environments. */
|
|
240486
|
-
if (windowResult.status !== "fulfilled" || typeof windowResult.value.windowId !== "number") return;
|
|
240487
|
-
await settleValueWithin(session.send("Browser.setWindowBounds", {
|
|
240488
|
-
bounds: {
|
|
240489
|
-
height: bounds.height,
|
|
240490
|
-
left: bounds.left ?? 0,
|
|
240491
|
-
top: bounds.top ?? 0,
|
|
240492
|
-
width: bounds.width,
|
|
240493
|
-
windowState: "normal"
|
|
240494
|
-
},
|
|
240495
|
-
windowId: windowResult.value.windowId
|
|
240496
|
-
}), TAB_CONTROL_TIMEOUT_MS);
|
|
240497
|
-
} finally {
|
|
240498
|
-
await settleValueWithin(session.detach(), TAB_CONTROL_TIMEOUT_MS);
|
|
240499
|
-
}
|
|
240500
|
-
}
|
|
240501
|
-
registerPage(page) {
|
|
240502
|
-
this.idFor(page);
|
|
240503
|
-
this.logsFor(page);
|
|
240504
|
-
if (this.registeredPages.has(page)) return;
|
|
240505
|
-
this.registeredPages.add(page);
|
|
240506
|
-
page.on("console", (message) => {
|
|
240507
|
-
this.logsFor(page).push(toConsoleLog(message, page.url()));
|
|
240508
|
-
});
|
|
240509
|
-
}
|
|
240510
|
-
idFor(page) {
|
|
240511
|
-
let id = this.pageIds.get(page);
|
|
240512
|
-
if (!id) {
|
|
240513
|
-
id = `tab_${randomUUID()}`;
|
|
240514
|
-
this.pageIds.set(page, id);
|
|
240515
|
-
}
|
|
240516
|
-
return id;
|
|
240517
|
-
}
|
|
240518
|
-
logsFor(page) {
|
|
240519
|
-
let entries = this.logs.get(page);
|
|
240520
|
-
if (!entries) {
|
|
240521
|
-
entries = [];
|
|
240522
|
-
this.logs.set(page, entries);
|
|
240523
|
-
}
|
|
240524
|
-
return entries;
|
|
240525
|
-
}
|
|
240526
|
-
};
|
|
240527
|
-
var PlaywrightTabHandle = class {
|
|
240528
|
-
page;
|
|
240529
|
-
id;
|
|
240530
|
-
logEntries;
|
|
240531
|
-
constructor(page, id, logEntries) {
|
|
240532
|
-
this.page = page;
|
|
240533
|
-
this.id = id;
|
|
240534
|
-
this.logEntries = logEntries;
|
|
240535
|
-
}
|
|
240536
|
-
async info() {
|
|
240537
|
-
const [title, history] = await Promise.all([settleValueWithin(this.page.title(), TAB_METADATA_TIMEOUT_MS), settleValueWithin(this.historyState(), TAB_METADATA_TIMEOUT_MS)]);
|
|
240538
|
-
const base = title.status !== "fulfilled" ? {
|
|
240539
|
-
id: this.id,
|
|
240540
|
-
url: this.page.url()
|
|
240541
|
-
} : {
|
|
240542
|
-
id: this.id,
|
|
240543
|
-
title: title.value,
|
|
240544
|
-
url: this.page.url()
|
|
240545
|
-
};
|
|
240546
|
-
/* v8 ignore next -- metadata timeout fallback is covered through AgentBrowser's bounded observation contract. */
|
|
240547
|
-
return history.status === "fulfilled" ? {
|
|
240548
|
-
...base,
|
|
240549
|
-
...history.value
|
|
240550
|
-
} : base;
|
|
240551
|
-
}
|
|
240552
|
-
async historyState() {
|
|
240553
|
-
const sessionResult = await settleValueWithin(this.page.context().newCDPSession(this.page), TAB_METADATA_TIMEOUT_MS);
|
|
240554
|
-
/* v8 ignore next -- Playwright CDP attachment failures are bounded and covered by the shared timeout primitive. */
|
|
240555
|
-
if (sessionResult.status !== "fulfilled") return {};
|
|
240556
|
-
const session = sessionResult.value;
|
|
240557
|
-
try {
|
|
240558
|
-
const historyResult = await settleValueWithin(session.send("Page.getNavigationHistory"), TAB_METADATA_TIMEOUT_MS);
|
|
240559
|
-
/* v8 ignore next -- Chromium navigation-history failures are bounded external CDP behavior. */
|
|
240560
|
-
if (historyResult.status !== "fulfilled") return {};
|
|
240561
|
-
const history = historyResult.value;
|
|
240562
|
-
return {
|
|
240563
|
-
canGoBack: history.currentIndex > 0,
|
|
240564
|
-
canGoForward: history.currentIndex < history.entries.length - 1
|
|
240565
|
-
};
|
|
240566
|
-
} finally {
|
|
240567
|
-
await settleValueWithin(session.detach(), TAB_METADATA_TIMEOUT_MS);
|
|
240568
|
-
}
|
|
240569
|
-
}
|
|
240570
|
-
async goto(url) {
|
|
240571
|
-
await this.page.goto(url, { waitUntil: "domcontentloaded" });
|
|
240572
|
-
}
|
|
240573
|
-
async reload() {
|
|
240574
|
-
await this.page.reload({ waitUntil: "domcontentloaded" });
|
|
240575
|
-
}
|
|
240576
|
-
async forceReload() {
|
|
240577
|
-
const client = await this.page.context().newCDPSession(this.page);
|
|
240578
|
-
try {
|
|
240579
|
-
await client.send("Page.reload", { ignoreCache: true });
|
|
240580
|
-
/* v8 ignore next -- defensive fallback for navigations that do not settle after CDP reload. */
|
|
240581
|
-
await this.page.waitForLoadState("domcontentloaded", { timeout: 3e4 }).catch(() => void 0);
|
|
240582
|
-
} finally {
|
|
240583
|
-
await client.detach();
|
|
240584
|
-
}
|
|
240585
|
-
}
|
|
240586
|
-
async back() {
|
|
240587
|
-
await this.page.goBack({ waitUntil: "domcontentloaded" });
|
|
240588
|
-
}
|
|
240589
|
-
async forward() {
|
|
240590
|
-
await this.page.goForward({ waitUntil: "domcontentloaded" });
|
|
240591
|
-
}
|
|
240592
|
-
async close() {
|
|
240593
|
-
await this.page.close();
|
|
240594
|
-
}
|
|
240595
|
-
async screenshot(options = {}) {
|
|
240596
|
-
const bytes = await this.page.screenshot({
|
|
240597
|
-
...options.fullPage === void 0 ? {} : { fullPage: options.fullPage },
|
|
240598
|
-
...options.clip === void 0 ? {} : { clip: options.clip },
|
|
240599
|
-
...options.mimeType === void 0 ? {} : { type: options.mimeType === "image/jpeg" ? "jpeg" : "png" },
|
|
240600
|
-
...options.quality === void 0 ? {} : { quality: options.quality }
|
|
240601
|
-
});
|
|
240602
|
-
if (options.maxBytes !== void 0 && bytes.byteLength > options.maxBytes) throw new Error(`Browser screenshot exceeded maxBytes=${options.maxBytes}. size=${bytes.byteLength}`);
|
|
240603
|
-
return bytes;
|
|
240604
|
-
}
|
|
240605
|
-
async setViewport(size) {
|
|
240606
|
-
await this.page.setViewportSize({
|
|
240607
|
-
width: Math.round(size.width),
|
|
240608
|
-
height: Math.round(size.height)
|
|
240609
|
-
});
|
|
240610
|
-
}
|
|
240611
|
-
async setZoom(zoom) {
|
|
240612
|
-
/* v8 ignore next 3 -- browser-executed callback runs outside Node coverage */
|
|
240613
|
-
await this.page.evaluate((level) => {
|
|
240614
|
-
document.documentElement.style.zoom = String(level);
|
|
240615
|
-
}, zoom.level);
|
|
240616
|
-
}
|
|
240617
|
-
async clearCookies() {
|
|
240618
|
-
await this.page.context().clearCookies();
|
|
240619
|
-
}
|
|
240620
|
-
async clearCache() {
|
|
240621
|
-
const client = await this.page.context().newCDPSession(this.page);
|
|
240622
|
-
try {
|
|
240623
|
-
await client.send("Network.clearBrowserCache");
|
|
240624
|
-
} finally {
|
|
240625
|
-
await client.detach();
|
|
240626
|
-
}
|
|
240627
|
-
}
|
|
240628
|
-
async domSnapshot() {
|
|
240629
|
-
return this.page.locator("body").ariaSnapshot({ timeout: 5e3 });
|
|
240630
|
-
}
|
|
240631
|
-
async evaluate(expression, arg) {
|
|
240632
|
-
/* v8 ignore next 4 -- browser-executed callback runs outside Node coverage */
|
|
240633
|
-
return this.page.evaluate((input) => {
|
|
240634
|
-
return new Function("arg", `return (${input.expression})(arg);`)(input.arg);
|
|
240635
|
-
}, {
|
|
240636
|
-
arg,
|
|
240637
|
-
expression
|
|
240638
|
-
});
|
|
240639
|
-
}
|
|
240640
|
-
async waitForLoadState(state = "load", timeoutMs) {
|
|
240641
|
-
await this.page.waitForLoadState(state, timeoutOptions(timeoutMs));
|
|
240642
|
-
}
|
|
240643
|
-
async waitForURL(url, timeoutMs) {
|
|
240644
|
-
await this.page.waitForURL(url, timeoutOptions(timeoutMs));
|
|
240645
|
-
}
|
|
240646
|
-
async waitForDownload(timeoutMs) {
|
|
240647
|
-
return toBrowserDownload(await this.page.waitForEvent("download", timeoutOptions(timeoutMs)));
|
|
240648
|
-
}
|
|
240649
|
-
async elementInfo(options) {
|
|
240650
|
-
/* v8 ignore start -- browser-executed DOM inspection runs outside Node coverage */
|
|
240651
|
-
return this.page.evaluate(({ x, y, includeNonInteractable }) => {
|
|
240652
|
-
const element = document.elementFromPoint(x, y);
|
|
240653
|
-
if (!element || element === document.documentElement || element === document.body) return;
|
|
240654
|
-
const rect = element.getBoundingClientRect();
|
|
240655
|
-
if (rect.width <= 0 || rect.height <= 0) return;
|
|
240656
|
-
const style = window.getComputedStyle(element);
|
|
240657
|
-
if (!includeNonInteractable && (style.visibility === "hidden" || style.display === "none" || style.pointerEvents === "none")) return;
|
|
240658
|
-
const tagName = element.tagName.toLowerCase();
|
|
240659
|
-
const visibleText = visibleElementText(element);
|
|
240660
|
-
const ariaName = element.getAttribute("aria-label") ?? element.getAttribute("alt") ?? void 0;
|
|
240661
|
-
const role = element.getAttribute("role") ?? inferRole(element);
|
|
240662
|
-
const candidates = selectorCandidates(element);
|
|
240663
|
-
const testId = element.getAttribute("data-testid") ?? element.getAttribute("data-test-id") ?? void 0;
|
|
240664
|
-
const nodeId = ensureNodeId(element);
|
|
240665
|
-
const preview = compactText(`${tagName}${role ? ` role=${role}` : ""}${ariaName ? ` aria="${ariaName}"` : ""}${visibleText ? ` text="${visibleText}"` : ""}`);
|
|
240666
|
-
return {
|
|
240667
|
-
...ariaName ? { ariaName } : {},
|
|
240668
|
-
boundingBox: {
|
|
240669
|
-
x: rect.x,
|
|
240670
|
-
y: rect.y,
|
|
240671
|
-
width: rect.width,
|
|
240672
|
-
height: rect.height
|
|
240673
|
-
},
|
|
240674
|
-
nodeId,
|
|
240675
|
-
preview,
|
|
240676
|
-
...role ? { role } : {},
|
|
240677
|
-
selector: {
|
|
240678
|
-
candidates,
|
|
240679
|
-
primary: candidates[0] ?? null
|
|
240680
|
-
},
|
|
240681
|
-
tagName,
|
|
240682
|
-
...testId ? { testId } : {},
|
|
240683
|
-
...visibleText ? { visibleText } : {}
|
|
240684
|
-
};
|
|
240685
|
-
function compactText(value) {
|
|
240686
|
-
return value.replace(/\s+/g, " ").trim().slice(0, 180);
|
|
240687
|
-
}
|
|
240688
|
-
function visibleElementText(node) {
|
|
240689
|
-
if (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement) return compactText(node.value || node.placeholder || "");
|
|
240690
|
-
if (node instanceof HTMLSelectElement) return compactText(node.selectedOptions[0]?.textContent ?? node.value);
|
|
240691
|
-
return compactText(node.textContent ?? "") || void 0;
|
|
240692
|
-
}
|
|
240693
|
-
function inferRole(node) {
|
|
240694
|
-
if (node instanceof HTMLAnchorElement && node.href) return "link";
|
|
240695
|
-
if (node instanceof HTMLButtonElement) return "button";
|
|
240696
|
-
if (node instanceof HTMLInputElement) return node.type || "textbox";
|
|
240697
|
-
if (node instanceof HTMLSelectElement) return "combobox";
|
|
240698
|
-
if (node instanceof HTMLTextAreaElement) return "textbox";
|
|
240699
|
-
if (/^h[1-6]$/i.test(node.tagName)) return "heading";
|
|
240700
|
-
}
|
|
240701
|
-
function ensureNodeId(node) {
|
|
240702
|
-
const existing = node.getAttribute("data-agent-browser-node-id");
|
|
240703
|
-
if (existing) return Number(existing);
|
|
240704
|
-
const next = Number(document.documentElement.getAttribute("data-agent-browser-next-node-id") ?? "1");
|
|
240705
|
-
document.documentElement.setAttribute("data-agent-browser-next-node-id", String(next + 1));
|
|
240706
|
-
node.setAttribute("data-agent-browser-node-id", String(next));
|
|
240707
|
-
return next;
|
|
240708
|
-
}
|
|
240709
|
-
function selectorCandidates(node) {
|
|
240710
|
-
const candidates = [];
|
|
240711
|
-
if (node.id) candidates.push(`#${cssEscape(node.id)}`);
|
|
240712
|
-
const testId = node.getAttribute("data-testid") ?? node.getAttribute("data-test-id");
|
|
240713
|
-
if (testId) candidates.push(`[data-testid="${cssString(testId)}"]`);
|
|
240714
|
-
const href = node.getAttribute("href");
|
|
240715
|
-
if (href) candidates.push(`${node.tagName.toLowerCase()}[href="${cssString(href)}"]`);
|
|
240716
|
-
const aria = node.getAttribute("aria-label");
|
|
240717
|
-
if (aria) candidates.push(`${node.tagName.toLowerCase()}[aria-label="${cssString(aria)}"]`);
|
|
240718
|
-
const name = node.getAttribute("name");
|
|
240719
|
-
if (name) candidates.push(`${node.tagName.toLowerCase()}[name="${cssString(name)}"]`);
|
|
240720
|
-
const parts = [];
|
|
240721
|
-
let current = node;
|
|
240722
|
-
while (current && current !== document.body && current !== document.documentElement && parts.length < 5) {
|
|
240723
|
-
let part = current.tagName.toLowerCase();
|
|
240724
|
-
const name = current.getAttribute("name");
|
|
240725
|
-
if (name) part += `[name="${cssString(name)}"]`;
|
|
240726
|
-
else {
|
|
240727
|
-
const className = Array.from(current.classList).find(Boolean);
|
|
240728
|
-
if (className) part += `.${cssEscape(className)}`;
|
|
240729
|
-
}
|
|
240730
|
-
const parent = current.parentElement;
|
|
240731
|
-
if (parent) {
|
|
240732
|
-
const siblings = Array.from(parent.children).filter((sibling) => sibling.tagName === current?.tagName);
|
|
240733
|
-
if (siblings.length > 1) part += `:nth-of-type(${siblings.indexOf(current) + 1})`;
|
|
240734
|
-
}
|
|
240735
|
-
parts.unshift(part);
|
|
240736
|
-
const candidate = parts.join(" > ");
|
|
240737
|
-
if (document.querySelectorAll(candidate).length === 1) {
|
|
240738
|
-
candidates.push(candidate);
|
|
240739
|
-
break;
|
|
240740
|
-
}
|
|
240741
|
-
current = parent;
|
|
240742
|
-
}
|
|
240743
|
-
const fallback = parts.join(" > ") || node.tagName.toLowerCase();
|
|
240744
|
-
candidates.push(fallback);
|
|
240745
|
-
return Array.from(new Set(candidates));
|
|
240746
|
-
}
|
|
240747
|
-
function cssEscape(value) {
|
|
240748
|
-
return CSS.escape(value);
|
|
240749
|
-
}
|
|
240750
|
-
function cssString(value) {
|
|
240751
|
-
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
240752
|
-
}
|
|
240753
|
-
}, options);
|
|
240754
|
-
/* v8 ignore stop */
|
|
240755
|
-
}
|
|
240756
|
-
async elementScreenshot(options) {
|
|
240757
|
-
const element = await this.elementInfo(options);
|
|
240758
|
-
if (!element?.boundingBox) return void 0;
|
|
240759
|
-
return this.screenshot({ clip: element.boundingBox });
|
|
240760
|
-
}
|
|
240761
|
-
async click(action) {
|
|
240762
|
-
const locator = this.locatorFor(action);
|
|
240763
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240764
|
-
await locator.click(timeoutOptions(action.timeoutMs));
|
|
240765
|
-
}
|
|
240766
|
-
async doubleClick(action) {
|
|
240767
|
-
const locator = this.locatorFor(action);
|
|
240768
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240769
|
-
await locator.dblclick(timeoutOptions(action.timeoutMs));
|
|
240770
|
-
}
|
|
240771
|
-
async fill(action, value) {
|
|
240772
|
-
const locator = this.locatorFor(action);
|
|
240773
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240774
|
-
await locator.fill(value, timeoutOptions(action.timeoutMs));
|
|
240775
|
-
}
|
|
240776
|
-
async type(action, value) {
|
|
240777
|
-
const locator = this.locatorFor(action);
|
|
240778
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240779
|
-
await locator.pressSequentially(value, timeoutOptions(action.timeoutMs));
|
|
240780
|
-
}
|
|
240781
|
-
async press(action, key) {
|
|
240782
|
-
const locator = this.locatorFor(action);
|
|
240783
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240784
|
-
await locator.press(key, timeoutOptions(action.timeoutMs));
|
|
240785
|
-
}
|
|
240786
|
-
async select(action, value) {
|
|
240787
|
-
const locator = this.locatorFor(action);
|
|
240788
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240789
|
-
await locator.selectOption(value, timeoutOptions(action.timeoutMs));
|
|
240790
|
-
}
|
|
240791
|
-
async check(action, checked) {
|
|
240792
|
-
const locator = this.locatorFor(action);
|
|
240793
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240794
|
-
await locator.setChecked(checked, timeoutOptions(action.timeoutMs));
|
|
240795
|
-
}
|
|
240796
|
-
async text(action) {
|
|
240797
|
-
const locator = this.locatorFor(action);
|
|
240798
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240799
|
-
return locator.textContent(timeoutOptions(action.timeoutMs));
|
|
240800
|
-
}
|
|
240801
|
-
async innerText(action) {
|
|
240802
|
-
const locator = this.locatorFor(action);
|
|
240803
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240804
|
-
return locator.innerText(timeoutOptions(action.timeoutMs));
|
|
240805
|
-
}
|
|
240806
|
-
async allTextContents(action) {
|
|
240807
|
-
return this.locatorFor(action).allTextContents();
|
|
240808
|
-
}
|
|
240809
|
-
async attribute(action, name) {
|
|
240810
|
-
const locator = this.locatorFor(action);
|
|
240811
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240812
|
-
return locator.getAttribute(name, timeoutOptions(action.timeoutMs));
|
|
240813
|
-
}
|
|
240814
|
-
async isVisible(action) {
|
|
240815
|
-
const locator = this.locatorFor(action);
|
|
240816
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240817
|
-
return locator.isVisible(timeoutOptions(action.timeoutMs));
|
|
240818
|
-
}
|
|
240819
|
-
async isEnabled(action) {
|
|
240820
|
-
const locator = this.locatorFor(action);
|
|
240821
|
-
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
240822
|
-
return locator.isEnabled(timeoutOptions(action.timeoutMs));
|
|
240823
|
-
}
|
|
240824
|
-
async locatorCount(action) {
|
|
240825
|
-
return this.locatorFor(action).count();
|
|
240826
|
-
}
|
|
240827
|
-
async waitForLocator(action, state) {
|
|
240828
|
-
await this.locatorFor(action).waitFor({
|
|
240829
|
-
...state === void 0 ? {} : { state },
|
|
240830
|
-
...timeoutOptions(action.timeoutMs)
|
|
240831
|
-
});
|
|
240832
|
-
}
|
|
240833
|
-
async cuaMove(point) {
|
|
240834
|
-
await this.page.mouse.move(point.x, point.y);
|
|
240835
|
-
}
|
|
240836
|
-
async cuaClick(point) {
|
|
240837
|
-
await this.page.mouse.click(point.x, point.y, { button: mouseButton(point.button) });
|
|
240838
|
-
}
|
|
240839
|
-
async cuaDoubleClick(point) {
|
|
240840
|
-
await this.page.mouse.dblclick(point.x, point.y);
|
|
240841
|
-
}
|
|
240842
|
-
async cuaDrag(path) {
|
|
240843
|
-
const [start, ...rest] = path;
|
|
240844
|
-
if (!start) return;
|
|
240845
|
-
await this.page.mouse.move(start.x, start.y);
|
|
240846
|
-
await this.page.mouse.down();
|
|
240847
|
-
for (const point of rest) await this.page.mouse.move(point.x, point.y);
|
|
240848
|
-
await this.page.mouse.up();
|
|
240849
|
-
}
|
|
240850
|
-
async cuaScroll(input) {
|
|
240851
|
-
await this.page.mouse.move(input.x, input.y);
|
|
240852
|
-
await this.page.mouse.wheel(input.scrollX, input.scrollY);
|
|
240853
|
-
}
|
|
240854
|
-
async cuaType(text) {
|
|
240855
|
-
await this.page.keyboard.type(text);
|
|
240856
|
-
}
|
|
240857
|
-
async cuaKeypress(keys) {
|
|
240858
|
-
await this.page.keyboard.press(keys.join("+"));
|
|
240859
|
-
}
|
|
240860
|
-
async visibleDom() {
|
|
240861
|
-
return this.page.evaluate(`(() => {
|
|
240862
|
-
let nextId = Number(document.documentElement.getAttribute("data-agent-browser-next-node-id") || "1");
|
|
240863
|
-
function walk(element) {
|
|
240864
|
-
const rect = element.getBoundingClientRect();
|
|
240865
|
-
const style = window.getComputedStyle(element);
|
|
240866
|
-
if (rect.width <= 0 || rect.height <= 0 || style.display === "none" || style.visibility === "hidden") {
|
|
240867
|
-
return undefined;
|
|
240868
|
-
}
|
|
240869
|
-
let nodeId = element.getAttribute("data-agent-browser-node-id");
|
|
240870
|
-
if (!nodeId) {
|
|
240871
|
-
nodeId = String(nextId++);
|
|
240872
|
-
element.setAttribute("data-agent-browser-node-id", nodeId);
|
|
240873
|
-
}
|
|
240874
|
-
const tagName = element.tagName.toLowerCase();
|
|
240875
|
-
const visibleText = (element.textContent ?? "").replace(/\s+/g, " ").trim().slice(0, 120) || undefined;
|
|
240876
|
-
const role = element.getAttribute("role") ?? undefined;
|
|
240877
|
-
const ariaName = element.getAttribute("aria-label") ?? undefined;
|
|
240878
|
-
const children = Array.from(element.children).map(walk).filter(Boolean);
|
|
240879
|
-
return {
|
|
240880
|
-
...(ariaName ? { ariaName } : {}),
|
|
240881
|
-
boundingBox: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
240882
|
-
...(children.length ? { children } : {}),
|
|
240883
|
-
nodeId,
|
|
240884
|
-
preview: (tagName + (ariaName ? ' "' + ariaName + '"' : "") + (visibleText ? " " + visibleText : "")).slice(0, 180),
|
|
240885
|
-
...(role ? { role } : {}),
|
|
240886
|
-
tagName,
|
|
240887
|
-
...(visibleText ? { visibleText } : {})
|
|
240888
|
-
};
|
|
240889
|
-
}
|
|
240890
|
-
document.documentElement.setAttribute("data-agent-browser-next-node-id", String(nextId));
|
|
240891
|
-
return walk(document.body) ?? { nodeId: "body", preview: "body", tagName: "body" };
|
|
240892
|
-
})()`);
|
|
240893
|
-
}
|
|
240894
|
-
async domClick(nodeId) {
|
|
240895
|
-
await this.byNodeId(nodeId).click();
|
|
240896
|
-
}
|
|
240897
|
-
async domDoubleClick(nodeId) {
|
|
240898
|
-
await this.byNodeId(nodeId).dblclick();
|
|
240899
|
-
}
|
|
240900
|
-
async domScroll(input) {
|
|
240901
|
-
if (input.nodeId) {
|
|
240902
|
-
/* v8 ignore next -- browser-executed DOM callback runs outside Node coverage */
|
|
240903
|
-
await this.byNodeId(input.nodeId).evaluate((element, delta) => element.scrollBy(delta.x, delta.y), {
|
|
240904
|
-
x: input.x,
|
|
240905
|
-
y: input.y
|
|
240906
|
-
});
|
|
240907
|
-
return;
|
|
240908
|
-
}
|
|
240909
|
-
await this.page.mouse.wheel(input.x, input.y);
|
|
240910
|
-
}
|
|
240911
|
-
async domType(text) {
|
|
240912
|
-
await this.page.keyboard.type(text);
|
|
240913
|
-
}
|
|
240914
|
-
async domKeypress(keys) {
|
|
240915
|
-
await this.page.keyboard.press(keys.join("+"));
|
|
240916
|
-
}
|
|
240917
|
-
async clipboardReadText() {
|
|
240918
|
-
/* v8 ignore next -- browser-executed callback runs outside Node coverage */
|
|
240919
|
-
return this.page.evaluate(() => navigator.clipboard.readText());
|
|
240920
|
-
}
|
|
240921
|
-
async clipboardWriteText(text) {
|
|
240922
|
-
/* v8 ignore next -- browser-executed callback runs outside Node coverage */
|
|
240923
|
-
await this.page.evaluate((value) => navigator.clipboard.writeText(value), text);
|
|
240924
|
-
}
|
|
240925
|
-
async logs(limit = 100) {
|
|
240926
|
-
return this.logEntries.slice(-limit);
|
|
240927
|
-
}
|
|
240928
|
-
byNodeId(nodeId) {
|
|
240929
|
-
return this.page.locator(`[data-agent-browser-node-id="${cssStringForSelector(nodeId)}"]`);
|
|
240930
|
-
}
|
|
240931
|
-
locatorFor(action) {
|
|
240932
|
-
return locatorForAction(this.page, action);
|
|
240933
|
-
}
|
|
240934
|
-
};
|
|
240935
|
-
function locatorActionLabel(action) {
|
|
240936
|
-
/* v8 ignore next -- valid public calls always supply selector or query; malformed calls are rejected downstream. */
|
|
240937
|
-
return action.selector ?? action.query?.kind ?? "locator";
|
|
240938
|
-
}
|
|
240939
|
-
function mouseButton(button) {
|
|
240940
|
-
if (button === 2) return "middle";
|
|
240941
|
-
if (button === 3) return "right";
|
|
240942
|
-
return "left";
|
|
240943
|
-
}
|
|
240944
|
-
function cssStringForSelector(value) {
|
|
240945
|
-
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
240946
|
-
}
|
|
240947
|
-
function timeoutOptions(timeoutMs) {
|
|
240948
|
-
return timeoutMs === void 0 ? {} : { timeout: timeoutMs };
|
|
240949
|
-
}
|
|
240950
|
-
function toBrowserDownload(download) {
|
|
240951
|
-
return {
|
|
240952
|
-
failure: () => download.failure(),
|
|
240953
|
-
path: () => download.path().catch(() => null),
|
|
240954
|
-
saveAs: (path) => download.saveAs(path),
|
|
240955
|
-
suggestedFilename: () => download.suggestedFilename(),
|
|
240956
|
-
url: () => download.url()
|
|
240957
|
-
};
|
|
240958
|
-
}
|
|
240959
|
-
async function assertSingle(countPromise, selector) {
|
|
240960
|
-
const count = await countPromise;
|
|
240961
|
-
if (count !== 1) throw new Error(`Selector must resolve to exactly one element. selector=${selector} count=${count}`);
|
|
240962
|
-
}
|
|
240963
|
-
function toConsoleLog(message, url) {
|
|
240964
|
-
return {
|
|
240965
|
-
level: normalizeLevel(message.type()),
|
|
240966
|
-
message: message.text(),
|
|
240967
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
240968
|
-
url
|
|
240969
|
-
};
|
|
240970
|
-
}
|
|
240971
|
-
function normalizeLevel(level) {
|
|
240972
|
-
if (level === "debug" || level === "info" || level === "log" || level === "warn" || level === "error") return level;
|
|
240973
|
-
/* v8 ignore next -- Playwright currently normalizes known console message types */
|
|
240974
|
-
return "log";
|
|
240975
|
-
}
|
|
240976
|
-
//#endregion
|
|
240977
240325
|
//#region ../../node_modules/.bun/debug@4.4.0+2b91fc17bf64bdfd/node_modules/debug/src/common.js
|
|
240978
240326
|
var require_common$2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
240979
240327
|
/**
|
|
@@ -268576,7 +267924,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
268576
267924
|
var dgram = __require("dgram");
|
|
268577
267925
|
var thunky = require_thunky();
|
|
268578
267926
|
var events = __require("events");
|
|
268579
|
-
var os
|
|
267927
|
+
var os = __require("os");
|
|
268580
267928
|
var noop = function() {};
|
|
268581
267929
|
module.exports = function(opts) {
|
|
268582
267930
|
if (!opts) opts = {};
|
|
@@ -268707,14 +268055,14 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
268707
268055
|
return that;
|
|
268708
268056
|
};
|
|
268709
268057
|
function defaultInterface() {
|
|
268710
|
-
var networks = os
|
|
268058
|
+
var networks = os.networkInterfaces();
|
|
268711
268059
|
var names = Object.keys(networks);
|
|
268712
268060
|
for (var i = 0; i < names.length; i++) {
|
|
268713
268061
|
var net = networks[names[i]];
|
|
268714
268062
|
for (var j = 0; j < net.length; j++) {
|
|
268715
268063
|
var iface = net[j];
|
|
268716
268064
|
if (isIPv4(iface.family) && !iface.internal) {
|
|
268717
|
-
if (os
|
|
268065
|
+
if (os.platform() === "darwin" && names[i] === "en0") return iface.address;
|
|
268718
268066
|
return "0.0.0.0";
|
|
268719
268067
|
}
|
|
268720
268068
|
}
|
|
@@ -268722,7 +268070,7 @@ var import_multicast_dns = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMi
|
|
|
268722
268070
|
return "127.0.0.1";
|
|
268723
268071
|
}
|
|
268724
268072
|
function allInterfaces() {
|
|
268725
|
-
var networks = os
|
|
268073
|
+
var networks = os.networkInterfaces();
|
|
268726
268074
|
var names = Object.keys(networks);
|
|
268727
268075
|
var res = [];
|
|
268728
268076
|
for (var i = 0; i < names.length; i++) {
|
|
@@ -284114,84 +283462,6 @@ function browserProfileSessionKey(sessionId) {
|
|
|
284114
283462
|
function browserProfileDirForSession(sessionId, root = AGENT_BROWSER_PROFILE_ROOT) {
|
|
284115
283463
|
return `${root}/${browserProfileSessionKey(sessionId)}`;
|
|
284116
283464
|
}
|
|
284117
|
-
const HOST_BRIDGE_RECONNECT_MAX_MS = 1e3;
|
|
284118
|
-
/**
|
|
284119
|
-
* Exponential backoff, capped.
|
|
284120
|
-
*
|
|
284121
|
-
* Pulled out of the retry loop so the curve can be asserted directly. Inline, it
|
|
284122
|
-
* was only ever exercised by waiting for a real reconnect.
|
|
284123
|
-
*/
|
|
284124
|
-
function hostBridgeReconnectDelayMs(attempt, baseMs = 25, maxMs = HOST_BRIDGE_RECONNECT_MAX_MS) {
|
|
284125
|
-
return Math.min(baseMs * 2 ** attempt, maxMs);
|
|
284126
|
-
}
|
|
284127
|
-
/** Bearer header, in one place so no call site invents its own casing. */
|
|
284128
|
-
function hostBridgeAuthHeaders(token) {
|
|
284129
|
-
return { authorization: `Bearer ${token}` };
|
|
284130
|
-
}
|
|
284131
|
-
/** Join a path onto a base URL, tolerating a base with or without a trailing slash. */
|
|
284132
|
-
function hostBridgePathUrl(baseUrl, path) {
|
|
284133
|
-
return new URL(path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString();
|
|
284134
|
-
}
|
|
284135
|
-
function hostBridgeQueryUrl(baseUrl, path, query) {
|
|
284136
|
-
const url = new URL(path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
|
|
284137
|
-
for (const [key, value] of Object.entries(query)) if (value) url.searchParams.set(key, value);
|
|
284138
|
-
return url.toString();
|
|
284139
|
-
}
|
|
284140
|
-
/**
|
|
284141
|
-
* Decode an error body from a fetch Response.
|
|
284142
|
-
*
|
|
284143
|
-
* Prefers a JSON `error` field, falls back to the raw body, then to the status
|
|
284144
|
-
* text. A server that returns HTML on failure would otherwise surface as an
|
|
284145
|
-
* empty message.
|
|
284146
|
-
*/
|
|
284147
|
-
async function readHostBridgeError(response) {
|
|
284148
|
-
const body = await response.text().catch(() => "");
|
|
284149
|
-
if (!body) return response.statusText || "Request failed.";
|
|
284150
|
-
try {
|
|
284151
|
-
const parsed = JSON.parse(body);
|
|
284152
|
-
if (typeof parsed.error === "string" && parsed.error.trim().length > 0) return parsed.error.trim();
|
|
284153
|
-
} catch {}
|
|
284154
|
-
return body.trim() || response.statusText || "Request failed.";
|
|
284155
|
-
}
|
|
284156
|
-
/** Collect a Node response body. Buffers because the bodies here are error text. */
|
|
284157
|
-
async function readHostBridgeNodeResponseBody(response) {
|
|
284158
|
-
const chunks = [];
|
|
284159
|
-
for await (const chunk of response) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
284160
|
-
return Buffer.concat(chunks).toString("utf8");
|
|
284161
|
-
}
|
|
284162
|
-
function formatHostBridgeNodeResponseError(statusCode, statusMessage, body, prefix) {
|
|
284163
|
-
const trimmedBody = body.trim();
|
|
284164
|
-
if (trimmedBody.length > 0) try {
|
|
284165
|
-
const parsed = JSON.parse(trimmedBody);
|
|
284166
|
-
if (typeof parsed.error === "string" && parsed.error.trim().length > 0) return parsed.error.trim();
|
|
284167
|
-
} catch {}
|
|
284168
|
-
const fallback = trimmedBody.length > 0 ? trimmedBody : statusMessage?.trim() || "Request failed.";
|
|
284169
|
-
return `${prefix}: ${statusCode ?? 0} ${fallback}`;
|
|
284170
|
-
}
|
|
284171
|
-
/** An abort that callers can recognise by name rather than by message matching. */
|
|
284172
|
-
function hostBridgeAbortError(message) {
|
|
284173
|
-
const error = new Error(message);
|
|
284174
|
-
error.name = "AbortError";
|
|
284175
|
-
return error;
|
|
284176
|
-
}
|
|
284177
|
-
/**
|
|
284178
|
-
* Drain complete NDJSON lines, returning what is left over.
|
|
284179
|
-
*
|
|
284180
|
-
* The remainder is the whole point: a stream chunk ends wherever the socket
|
|
284181
|
-
* decides, so the trailing line is usually incomplete and must be carried into
|
|
284182
|
-
* the next chunk rather than parsed.
|
|
284183
|
-
*/
|
|
284184
|
-
function drainHostBridgeNdjsonBuffer(buffer, callback, parseLine = (line) => JSON.parse(line)) {
|
|
284185
|
-
let nextBuffer = buffer;
|
|
284186
|
-
let newlineIndex = nextBuffer.indexOf("\n");
|
|
284187
|
-
while (newlineIndex >= 0) {
|
|
284188
|
-
const line = nextBuffer.slice(0, newlineIndex).trim();
|
|
284189
|
-
nextBuffer = nextBuffer.slice(newlineIndex + 1);
|
|
284190
|
-
if (line.length > 0) callback(parseLine(line));
|
|
284191
|
-
newlineIndex = nextBuffer.indexOf("\n");
|
|
284192
|
-
}
|
|
284193
|
-
return nextBuffer;
|
|
284194
|
-
}
|
|
284195
283465
|
//#endregion
|
|
284196
283466
|
//#region src/browser/Layers/BrowserOrphanReaper.ts
|
|
284197
283467
|
/**
|
|
@@ -284531,6 +283801,301 @@ function browserControlRejectionDetail(decision) {
|
|
|
284531
283801
|
case "incomplete_metadata": return "Browser control ordering requires both sessionEpoch and controlSequence.";
|
|
284532
283802
|
}
|
|
284533
283803
|
}
|
|
283804
|
+
const HOST_BRIDGE_RECONNECT_MAX_MS = 1e3;
|
|
283805
|
+
/**
|
|
283806
|
+
* Exponential backoff, capped.
|
|
283807
|
+
*
|
|
283808
|
+
* Pulled out of the retry loop so the curve can be asserted directly. Inline, it
|
|
283809
|
+
* was only ever exercised by waiting for a real reconnect.
|
|
283810
|
+
*/
|
|
283811
|
+
function hostBridgeReconnectDelayMs(attempt, baseMs = 25, maxMs = HOST_BRIDGE_RECONNECT_MAX_MS) {
|
|
283812
|
+
return Math.min(baseMs * 2 ** attempt, maxMs);
|
|
283813
|
+
}
|
|
283814
|
+
/** Bearer header, in one place so no call site invents its own casing. */
|
|
283815
|
+
function hostBridgeAuthHeaders(token) {
|
|
283816
|
+
return { authorization: `Bearer ${token}` };
|
|
283817
|
+
}
|
|
283818
|
+
/** Join a path onto a base URL, tolerating a base with or without a trailing slash. */
|
|
283819
|
+
function hostBridgePathUrl(baseUrl, path) {
|
|
283820
|
+
return new URL(path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`).toString();
|
|
283821
|
+
}
|
|
283822
|
+
function hostBridgeQueryUrl(baseUrl, path, query) {
|
|
283823
|
+
const url = new URL(path, baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`);
|
|
283824
|
+
for (const [key, value] of Object.entries(query)) if (value) url.searchParams.set(key, value);
|
|
283825
|
+
return url.toString();
|
|
283826
|
+
}
|
|
283827
|
+
/**
|
|
283828
|
+
* Decode an error body from a fetch Response.
|
|
283829
|
+
*
|
|
283830
|
+
* Prefers a JSON `error` field, falls back to the raw body, then to the status
|
|
283831
|
+
* text. A server that returns HTML on failure would otherwise surface as an
|
|
283832
|
+
* empty message.
|
|
283833
|
+
*/
|
|
283834
|
+
async function readHostBridgeError(response) {
|
|
283835
|
+
const body = await response.text().catch(() => "");
|
|
283836
|
+
if (!body) return response.statusText || "Request failed.";
|
|
283837
|
+
try {
|
|
283838
|
+
const parsed = JSON.parse(body);
|
|
283839
|
+
if (typeof parsed.error === "string" && parsed.error.trim().length > 0) return parsed.error.trim();
|
|
283840
|
+
} catch {}
|
|
283841
|
+
return body.trim() || response.statusText || "Request failed.";
|
|
283842
|
+
}
|
|
283843
|
+
/** Collect a Node response body. Buffers because the bodies here are error text. */
|
|
283844
|
+
async function readHostBridgeNodeResponseBody(response) {
|
|
283845
|
+
const chunks = [];
|
|
283846
|
+
for await (const chunk of response) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
283847
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
283848
|
+
}
|
|
283849
|
+
function formatHostBridgeNodeResponseError(statusCode, statusMessage, body, prefix) {
|
|
283850
|
+
const trimmedBody = body.trim();
|
|
283851
|
+
if (trimmedBody.length > 0) try {
|
|
283852
|
+
const parsed = JSON.parse(trimmedBody);
|
|
283853
|
+
if (typeof parsed.error === "string" && parsed.error.trim().length > 0) return parsed.error.trim();
|
|
283854
|
+
} catch {}
|
|
283855
|
+
const fallback = trimmedBody.length > 0 ? trimmedBody : statusMessage?.trim() || "Request failed.";
|
|
283856
|
+
return `${prefix}: ${statusCode ?? 0} ${fallback}`;
|
|
283857
|
+
}
|
|
283858
|
+
/** An abort that callers can recognise by name rather than by message matching. */
|
|
283859
|
+
function hostBridgeAbortError(message) {
|
|
283860
|
+
const error = new Error(message);
|
|
283861
|
+
error.name = "AbortError";
|
|
283862
|
+
return error;
|
|
283863
|
+
}
|
|
283864
|
+
/**
|
|
283865
|
+
* Drain complete NDJSON lines, returning what is left over.
|
|
283866
|
+
*
|
|
283867
|
+
* The remainder is the whole point: a stream chunk ends wherever the socket
|
|
283868
|
+
* decides, so the trailing line is usually incomplete and must be carried into
|
|
283869
|
+
* the next chunk rather than parsed.
|
|
283870
|
+
*/
|
|
283871
|
+
function drainHostBridgeNdjsonBuffer(buffer, callback, parseLine = (line) => JSON.parse(line)) {
|
|
283872
|
+
let nextBuffer = buffer;
|
|
283873
|
+
let newlineIndex = nextBuffer.indexOf("\n");
|
|
283874
|
+
while (newlineIndex >= 0) {
|
|
283875
|
+
const line = nextBuffer.slice(0, newlineIndex).trim();
|
|
283876
|
+
nextBuffer = nextBuffer.slice(newlineIndex + 1);
|
|
283877
|
+
if (line.length > 0) callback(parseLine(line));
|
|
283878
|
+
newlineIndex = nextBuffer.indexOf("\n");
|
|
283879
|
+
}
|
|
283880
|
+
return nextBuffer;
|
|
283881
|
+
}
|
|
283882
|
+
//#endregion
|
|
283883
|
+
//#region src/browser/NativeHostBrowserBridgeClient.ts
|
|
283884
|
+
const NATIVE_HOST_EVENT_RECONNECT_BASE_MS = 25;
|
|
283885
|
+
const NATIVE_HOST_EVENT_RECONNECT_MAX_MS = HOST_BRIDGE_RECONNECT_MAX_MS;
|
|
283886
|
+
function nativeHostBridgeUrl(baseUrl) {
|
|
283887
|
+
return hostBridgePathUrl(baseUrl, "/agent-browser/host-bridge");
|
|
283888
|
+
}
|
|
283889
|
+
function nativeHostBridgeEventsUrl(baseUrl, input) {
|
|
283890
|
+
return hostBridgeQueryUrl(baseUrl, "/agent-browser/host-events", {
|
|
283891
|
+
browserId: input.browserId,
|
|
283892
|
+
sessionId: input.sessionId
|
|
283893
|
+
});
|
|
283894
|
+
}
|
|
283895
|
+
async function readNativeHostBridgeError(response) {
|
|
283896
|
+
return readHostBridgeError(response);
|
|
283897
|
+
}
|
|
283898
|
+
async function readNativeHostBridgeNodeResponseBody(response) {
|
|
283899
|
+
return readHostBridgeNodeResponseBody(response);
|
|
283900
|
+
}
|
|
283901
|
+
function formatNativeHostBridgeNodeResponseError(statusCode, statusMessage, body) {
|
|
283902
|
+
return formatHostBridgeNodeResponseError(statusCode, statusMessage, body, "Native browser host bridge event stream failed");
|
|
283903
|
+
}
|
|
283904
|
+
function nativeHostBridgeAbortError() {
|
|
283905
|
+
return hostBridgeAbortError("Native browser host bridge event stream aborted.");
|
|
283906
|
+
}
|
|
283907
|
+
function parseNativeHostBridgeEventLine(line) {
|
|
283908
|
+
return JSON.parse(line);
|
|
283909
|
+
}
|
|
283910
|
+
function drainNativeHostBridgeNdjsonBuffer(buffer, callback) {
|
|
283911
|
+
return drainHostBridgeNdjsonBuffer(buffer, callback, parseNativeHostBridgeEventLine);
|
|
283912
|
+
}
|
|
283913
|
+
function subscribeToNativeHostBridgeEventsViaNodeHttp(input) {
|
|
283914
|
+
return new Promise((resolve, reject) => {
|
|
283915
|
+
if (input.abortSignal.aborted) {
|
|
283916
|
+
resolve();
|
|
283917
|
+
return;
|
|
283918
|
+
}
|
|
283919
|
+
const url = new URL(nativeHostBridgeEventsUrl(input.options.baseUrl, input.input));
|
|
283920
|
+
const transport = url.protocol === "https:" ? https : http;
|
|
283921
|
+
let settled = false;
|
|
283922
|
+
const finalize = (handler) => {
|
|
283923
|
+
if (settled) return;
|
|
283924
|
+
settled = true;
|
|
283925
|
+
input.abortSignal.removeEventListener("abort", onAbort);
|
|
283926
|
+
handler();
|
|
283927
|
+
};
|
|
283928
|
+
const onAbort = () => {
|
|
283929
|
+
request.destroy(nativeHostBridgeAbortError());
|
|
283930
|
+
finalize(resolve);
|
|
283931
|
+
};
|
|
283932
|
+
const request = transport.request({
|
|
283933
|
+
protocol: url.protocol,
|
|
283934
|
+
hostname: url.hostname,
|
|
283935
|
+
port: url.port,
|
|
283936
|
+
path: `${url.pathname}${url.search}`,
|
|
283937
|
+
method: "GET",
|
|
283938
|
+
headers: hostBridgeAuthHeaders(input.options.token)
|
|
283939
|
+
}, (response) => {
|
|
283940
|
+
const statusCode = response.statusCode ?? 0;
|
|
283941
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
283942
|
+
readNativeHostBridgeNodeResponseBody(response).then((body) => finalize(() => reject(new Error(formatNativeHostBridgeNodeResponseError(response.statusCode, response.statusMessage, body))))).catch((error) => finalize(() => reject(error)));
|
|
283943
|
+
return;
|
|
283944
|
+
}
|
|
283945
|
+
response.setEncoding("utf8");
|
|
283946
|
+
let buffer = "";
|
|
283947
|
+
const rejectStream = (error) => {
|
|
283948
|
+
const streamError = error instanceof Error ? error : new Error(String(error ?? "Unknown stream failure"));
|
|
283949
|
+
response.destroy(streamError);
|
|
283950
|
+
finalize(() => reject(streamError));
|
|
283951
|
+
};
|
|
283952
|
+
response.on("data", (chunk) => {
|
|
283953
|
+
try {
|
|
283954
|
+
buffer = drainNativeHostBridgeNdjsonBuffer(buffer + (typeof chunk === "string" ? chunk : chunk.toString("utf8")), input.callback);
|
|
283955
|
+
} catch (error) {
|
|
283956
|
+
rejectStream(error);
|
|
283957
|
+
}
|
|
283958
|
+
});
|
|
283959
|
+
response.on("end", () => finalize(resolve));
|
|
283960
|
+
response.on("close", () => finalize(resolve));
|
|
283961
|
+
response.on("error", (error) => finalize(() => reject(error)));
|
|
283962
|
+
});
|
|
283963
|
+
request.on("socket", (socket) => {
|
|
283964
|
+
socket.setKeepAlive(true, 1e3);
|
|
283965
|
+
});
|
|
283966
|
+
request.on("error", (error) => {
|
|
283967
|
+
if (input.abortSignal.aborted && error.name === "AbortError") {
|
|
283968
|
+
finalize(resolve);
|
|
283969
|
+
return;
|
|
283970
|
+
}
|
|
283971
|
+
finalize(() => reject(error));
|
|
283972
|
+
});
|
|
283973
|
+
input.abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
283974
|
+
request.end();
|
|
283975
|
+
});
|
|
283976
|
+
}
|
|
283977
|
+
async function requestNativeHostBridge(input) {
|
|
283978
|
+
const abortController = new AbortController();
|
|
283979
|
+
const timeout = setTimeout(() => abortController.abort(), input.method === "closeSession" ? input.deps.closeSessionTimeoutMs() : 3e4);
|
|
283980
|
+
const response = await input.fetchImpl(nativeHostBridgeUrl(input.options.baseUrl), {
|
|
283981
|
+
method: "POST",
|
|
283982
|
+
headers: {
|
|
283983
|
+
authorization: `Bearer ${input.options.token}`,
|
|
283984
|
+
"content-type": "application/json"
|
|
283985
|
+
},
|
|
283986
|
+
body: JSON.stringify({
|
|
283987
|
+
method: input.method,
|
|
283988
|
+
params: input.params
|
|
283989
|
+
}),
|
|
283990
|
+
signal: abortController.signal
|
|
283991
|
+
}).finally(() => {
|
|
283992
|
+
clearTimeout(timeout);
|
|
283993
|
+
});
|
|
283994
|
+
if (!response.ok) {
|
|
283995
|
+
const message = await readNativeHostBridgeError(response);
|
|
283996
|
+
throw new Error(`Native browser host bridge request failed: ${response.status} ${message}`);
|
|
283997
|
+
}
|
|
283998
|
+
return (await response.json()).result;
|
|
283999
|
+
}
|
|
284000
|
+
async function readNativeHostBridgeEventsViaFetch(input) {
|
|
284001
|
+
const response = await input.fetchImpl(nativeHostBridgeEventsUrl(input.options.baseUrl, input.identity), {
|
|
284002
|
+
headers: { authorization: `Bearer ${input.options.token}` },
|
|
284003
|
+
signal: input.abortSignal
|
|
284004
|
+
});
|
|
284005
|
+
if (!response.ok) {
|
|
284006
|
+
const message = await readNativeHostBridgeError(response);
|
|
284007
|
+
throw new Error(`Native browser host bridge event stream failed: ${response.status} ${message}`);
|
|
284008
|
+
}
|
|
284009
|
+
const reader = response.body?.getReader();
|
|
284010
|
+
if (!reader) throw new Error("Native browser host bridge event stream is unavailable.");
|
|
284011
|
+
await readNativeHostBridgeEventReader(reader, input);
|
|
284012
|
+
}
|
|
284013
|
+
async function readNativeHostBridgeEventReader(reader, input) {
|
|
284014
|
+
const decoder = new TextDecoder();
|
|
284015
|
+
let buffer = "";
|
|
284016
|
+
while (!input.abortSignal.aborted) {
|
|
284017
|
+
const { done, value } = await reader.read();
|
|
284018
|
+
if (done) return;
|
|
284019
|
+
buffer = drainNativeHostBridgeNdjsonBuffer(buffer + decoder.decode(value, { stream: true }), input.callback);
|
|
284020
|
+
}
|
|
284021
|
+
}
|
|
284022
|
+
async function readNativeHostBridgeEvents(input) {
|
|
284023
|
+
if (!input.options.fetch) {
|
|
284024
|
+
await subscribeToNativeHostBridgeEventsViaNodeHttp({
|
|
284025
|
+
abortSignal: input.abortSignal,
|
|
284026
|
+
callback: input.callback,
|
|
284027
|
+
input: input.identity,
|
|
284028
|
+
options: input.options
|
|
284029
|
+
});
|
|
284030
|
+
return;
|
|
284031
|
+
}
|
|
284032
|
+
await readNativeHostBridgeEventsViaFetch(input);
|
|
284033
|
+
}
|
|
284034
|
+
function abortableDelay(ms, signal) {
|
|
284035
|
+
if (signal.aborted) return Promise.resolve();
|
|
284036
|
+
return new Promise((resolve) => {
|
|
284037
|
+
const timeout = setTimeout(resolve, ms);
|
|
284038
|
+
signal.addEventListener("abort", () => {
|
|
284039
|
+
clearTimeout(timeout);
|
|
284040
|
+
resolve();
|
|
284041
|
+
}, { once: true });
|
|
284042
|
+
});
|
|
284043
|
+
}
|
|
284044
|
+
async function maintainNativeHostBridgeEventSubscription(input) {
|
|
284045
|
+
let attempt = 0;
|
|
284046
|
+
while (!input.abortSignal.aborted) {
|
|
284047
|
+
try {
|
|
284048
|
+
await readNativeHostBridgeEvents(input);
|
|
284049
|
+
attempt = 0;
|
|
284050
|
+
} catch (error) {
|
|
284051
|
+
if (input.abortSignal.aborted) return;
|
|
284052
|
+
console.warn("[browser] native host bridge event stream failed", error);
|
|
284053
|
+
}
|
|
284054
|
+
if (!input.abortSignal.aborted) {
|
|
284055
|
+
const delayMs = hostBridgeReconnectDelayMs(attempt, NATIVE_HOST_EVENT_RECONNECT_BASE_MS, NATIVE_HOST_EVENT_RECONNECT_MAX_MS);
|
|
284056
|
+
attempt += 1;
|
|
284057
|
+
await abortableDelay(delayMs, input.abortSignal);
|
|
284058
|
+
}
|
|
284059
|
+
}
|
|
284060
|
+
}
|
|
284061
|
+
function subscribeToNativeHostBridgeEvents(input) {
|
|
284062
|
+
const abortController = new AbortController();
|
|
284063
|
+
maintainNativeHostBridgeEventSubscription({
|
|
284064
|
+
abortSignal: abortController.signal,
|
|
284065
|
+
callback: input.callback,
|
|
284066
|
+
fetchImpl: input.fetchImpl,
|
|
284067
|
+
identity: input.identity,
|
|
284068
|
+
options: input.options
|
|
284069
|
+
});
|
|
284070
|
+
return () => {
|
|
284071
|
+
abortController.abort();
|
|
284072
|
+
};
|
|
284073
|
+
}
|
|
284074
|
+
function createNativeHostBrowserBridgeClientImplementation(options, deps) {
|
|
284075
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
284076
|
+
const request = (method, params) => requestNativeHostBridge({
|
|
284077
|
+
deps,
|
|
284078
|
+
fetchImpl,
|
|
284079
|
+
method,
|
|
284080
|
+
options,
|
|
284081
|
+
params
|
|
284082
|
+
});
|
|
284083
|
+
const subscribe = (identity, callback) => subscribeToNativeHostBridgeEvents({
|
|
284084
|
+
callback,
|
|
284085
|
+
fetchImpl,
|
|
284086
|
+
identity,
|
|
284087
|
+
options
|
|
284088
|
+
});
|
|
284089
|
+
return {
|
|
284090
|
+
closeSession: (input = {}) => request("closeSession", input),
|
|
284091
|
+
command: (input) => request("command", input),
|
|
284092
|
+
getSession: (input = {}) => request("getSession", input),
|
|
284093
|
+
listSessions: (input = {}) => request("listSessions", input),
|
|
284094
|
+
onEvent: subscribe,
|
|
284095
|
+
openSession: (input = {}) => request("openSession", input),
|
|
284096
|
+
subscribe: async (input, callback) => subscribe(input, callback)
|
|
284097
|
+
};
|
|
284098
|
+
}
|
|
284534
284099
|
//#endregion
|
|
284535
284100
|
//#region src/browser/AgentBrowserHostBridgeAdapter.ts
|
|
284536
284101
|
const DEFAULT_URL = "about:blank";
|
|
@@ -284540,8 +284105,6 @@ const DEFAULT_AGENT_BROWSER_VIEWPORT = {
|
|
|
284540
284105
|
width: 1280,
|
|
284541
284106
|
height: 720
|
|
284542
284107
|
};
|
|
284543
|
-
const NATIVE_HOST_EVENT_RECONNECT_BASE_MS = 25;
|
|
284544
|
-
const NATIVE_HOST_EVENT_RECONNECT_MAX_MS = HOST_BRIDGE_RECONNECT_MAX_MS;
|
|
284545
284108
|
const ABSOLUTE_WEB_URL_PATTERN = /^[a-z][a-z\d+\-.]*:\/\//i;
|
|
284546
284109
|
const SPECIAL_URL_PATTERN = /^(about|blob|chrome|data|devtools|file):/i;
|
|
284547
284110
|
const LOCAL_URL_LIKE_PATTERN = /^(localhost|127\.0\.0\.1|\[::1\]|::1|[a-z0-9.-]+\.localhost)(?::\d+)?(?:[/?#].*)?$/i;
|
|
@@ -284680,11 +284243,26 @@ async function closeAgentBrowserBackendWithTimeout(closeBackend, env = process.e
|
|
|
284680
284243
|
console.warn("[browser] Agent Browser Playwright backend close timed out; continuing", { timeoutMs: agentBrowserPlaywrightBackendCloseTimeoutMs(env) });
|
|
284681
284244
|
}
|
|
284682
284245
|
}
|
|
284683
|
-
|
|
284684
|
-
|
|
284685
|
-
|
|
284246
|
+
function createNativeHostBrowserBridgeClient(options) {
|
|
284247
|
+
return createNativeHostBrowserBridgeClientImplementation(options, { closeSessionTimeoutMs: agentBrowserCloseTimeoutMs });
|
|
284248
|
+
}
|
|
284249
|
+
/**
|
|
284250
|
+
* Builds the Playwright-backed backend from the lazily loaded module. The
|
|
284251
|
+
* `playwright` package (and everything that statically imports it) must stay
|
|
284252
|
+
* out of the standalone bundle's eager import graph: the bundle keeps
|
|
284253
|
+
* `playwright` external, so a static import would hoist it to the top of
|
|
284254
|
+
* `dist/bin.mjs` and the server would fail to boot on any machine that has
|
|
284255
|
+
* not provisioned playwright yet. Deferring the import to backend construction
|
|
284256
|
+
* keeps boot playwright-free and lets a later provision satisfy first use.
|
|
284257
|
+
*/
|
|
284258
|
+
function createForgeAgentBrowserPlaywrightBackend(PlaywrightBackend, options) {
|
|
284259
|
+
class ForgeAgentBrowserPlaywrightBackend extends PlaywrightBackend {
|
|
284260
|
+
async close() {
|
|
284261
|
+
await closeAgentBrowserBackendWithTimeout(() => super.close());
|
|
284262
|
+
}
|
|
284686
284263
|
}
|
|
284687
|
-
|
|
284264
|
+
return new ForgeAgentBrowserPlaywrightBackend(options);
|
|
284265
|
+
}
|
|
284688
284266
|
function toBrowserError(error, fallback) {
|
|
284689
284267
|
console.warn("[browser] Agent Browser host bridge operation failed", {
|
|
284690
284268
|
operation: fallback,
|
|
@@ -284807,193 +284385,6 @@ function resolveDisplay(snapshot, options) {
|
|
|
284807
284385
|
if (typeof options?.display === "function") return options.display(snapshot);
|
|
284808
284386
|
return options?.display ?? DEFAULT_AGENT_BROWSER_DISPLAY;
|
|
284809
284387
|
}
|
|
284810
|
-
function nativeHostBridgeUrl(baseUrl) {
|
|
284811
|
-
return hostBridgePathUrl(baseUrl, "/agent-browser/host-bridge");
|
|
284812
|
-
}
|
|
284813
|
-
function nativeHostBridgeEventsUrl(baseUrl, input) {
|
|
284814
|
-
return hostBridgeQueryUrl(baseUrl, "/agent-browser/host-events", {
|
|
284815
|
-
browserId: input.browserId,
|
|
284816
|
-
sessionId: input.sessionId
|
|
284817
|
-
});
|
|
284818
|
-
}
|
|
284819
|
-
async function readNativeHostBridgeError(response) {
|
|
284820
|
-
return readHostBridgeError(response);
|
|
284821
|
-
}
|
|
284822
|
-
async function readNativeHostBridgeNodeResponseBody(response) {
|
|
284823
|
-
return readHostBridgeNodeResponseBody(response);
|
|
284824
|
-
}
|
|
284825
|
-
function formatNativeHostBridgeNodeResponseError(statusCode, statusMessage, body) {
|
|
284826
|
-
return formatHostBridgeNodeResponseError(statusCode, statusMessage, body, "Native browser host bridge event stream failed");
|
|
284827
|
-
}
|
|
284828
|
-
function nativeHostBridgeAbortError() {
|
|
284829
|
-
return hostBridgeAbortError("Native browser host bridge event stream aborted.");
|
|
284830
|
-
}
|
|
284831
|
-
function parseNativeHostBridgeEventLine(line) {
|
|
284832
|
-
return JSON.parse(line);
|
|
284833
|
-
}
|
|
284834
|
-
function drainNativeHostBridgeNdjsonBuffer(buffer, callback) {
|
|
284835
|
-
return drainHostBridgeNdjsonBuffer(buffer, callback, parseNativeHostBridgeEventLine);
|
|
284836
|
-
}
|
|
284837
|
-
function subscribeToNativeHostBridgeEventsViaNodeHttp(input) {
|
|
284838
|
-
return new Promise((resolve, reject) => {
|
|
284839
|
-
if (input.abortSignal.aborted) {
|
|
284840
|
-
resolve();
|
|
284841
|
-
return;
|
|
284842
|
-
}
|
|
284843
|
-
const url = new URL(nativeHostBridgeEventsUrl(input.options.baseUrl, input.input));
|
|
284844
|
-
const transport = url.protocol === "https:" ? https : http;
|
|
284845
|
-
let settled = false;
|
|
284846
|
-
const finalize = (handler) => {
|
|
284847
|
-
if (settled) return;
|
|
284848
|
-
settled = true;
|
|
284849
|
-
input.abortSignal.removeEventListener("abort", onAbort);
|
|
284850
|
-
handler();
|
|
284851
|
-
};
|
|
284852
|
-
const onAbort = () => {
|
|
284853
|
-
request.destroy(nativeHostBridgeAbortError());
|
|
284854
|
-
finalize(resolve);
|
|
284855
|
-
};
|
|
284856
|
-
const request = transport.request({
|
|
284857
|
-
protocol: url.protocol,
|
|
284858
|
-
hostname: url.hostname,
|
|
284859
|
-
port: url.port,
|
|
284860
|
-
path: `${url.pathname}${url.search}`,
|
|
284861
|
-
method: "GET",
|
|
284862
|
-
headers: hostBridgeAuthHeaders(input.options.token)
|
|
284863
|
-
}, (response) => {
|
|
284864
|
-
const statusCode = response.statusCode ?? 0;
|
|
284865
|
-
if (statusCode < 200 || statusCode >= 300) {
|
|
284866
|
-
readNativeHostBridgeNodeResponseBody(response).then((body) => finalize(() => reject(new Error(formatNativeHostBridgeNodeResponseError(response.statusCode, response.statusMessage, body))))).catch((error) => finalize(() => reject(error)));
|
|
284867
|
-
return;
|
|
284868
|
-
}
|
|
284869
|
-
response.setEncoding("utf8");
|
|
284870
|
-
let buffer = "";
|
|
284871
|
-
const rejectStream = (error) => {
|
|
284872
|
-
const streamError = error instanceof Error ? error : new Error(String(error ?? "Unknown stream failure"));
|
|
284873
|
-
response.destroy(streamError);
|
|
284874
|
-
finalize(() => reject(streamError));
|
|
284875
|
-
};
|
|
284876
|
-
response.on("data", (chunk) => {
|
|
284877
|
-
try {
|
|
284878
|
-
buffer = drainNativeHostBridgeNdjsonBuffer(buffer + (typeof chunk === "string" ? chunk : chunk.toString("utf8")), input.callback);
|
|
284879
|
-
} catch (error) {
|
|
284880
|
-
rejectStream(error);
|
|
284881
|
-
}
|
|
284882
|
-
});
|
|
284883
|
-
response.on("end", () => finalize(resolve));
|
|
284884
|
-
response.on("close", () => finalize(resolve));
|
|
284885
|
-
response.on("error", (error) => finalize(() => reject(error)));
|
|
284886
|
-
});
|
|
284887
|
-
request.on("socket", (socket) => {
|
|
284888
|
-
socket.setKeepAlive(true, 1e3);
|
|
284889
|
-
});
|
|
284890
|
-
request.on("error", (error) => {
|
|
284891
|
-
if (input.abortSignal.aborted && error.name === "AbortError") {
|
|
284892
|
-
finalize(resolve);
|
|
284893
|
-
return;
|
|
284894
|
-
}
|
|
284895
|
-
finalize(() => reject(error));
|
|
284896
|
-
});
|
|
284897
|
-
input.abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
284898
|
-
request.end();
|
|
284899
|
-
});
|
|
284900
|
-
}
|
|
284901
|
-
function abortableDelay(ms, signal) {
|
|
284902
|
-
if (signal.aborted) return Promise.resolve();
|
|
284903
|
-
return new Promise((resolve) => {
|
|
284904
|
-
const timeout = setTimeout(resolve, ms);
|
|
284905
|
-
signal.addEventListener("abort", () => {
|
|
284906
|
-
clearTimeout(timeout);
|
|
284907
|
-
resolve();
|
|
284908
|
-
}, { once: true });
|
|
284909
|
-
});
|
|
284910
|
-
}
|
|
284911
|
-
function createNativeHostBrowserBridgeClient(options) {
|
|
284912
|
-
const fetchImpl = options.fetch ?? fetch;
|
|
284913
|
-
const request = async (method, params) => {
|
|
284914
|
-
const abortController = new AbortController();
|
|
284915
|
-
const timeout = setTimeout(() => abortController.abort(), method === "closeSession" ? agentBrowserCloseTimeoutMs() : 3e4);
|
|
284916
|
-
const response = await fetchImpl(nativeHostBridgeUrl(options.baseUrl), {
|
|
284917
|
-
method: "POST",
|
|
284918
|
-
headers: {
|
|
284919
|
-
authorization: `Bearer ${options.token}`,
|
|
284920
|
-
"content-type": "application/json"
|
|
284921
|
-
},
|
|
284922
|
-
body: JSON.stringify({
|
|
284923
|
-
method,
|
|
284924
|
-
params
|
|
284925
|
-
}),
|
|
284926
|
-
signal: abortController.signal
|
|
284927
|
-
}).finally(() => {
|
|
284928
|
-
clearTimeout(timeout);
|
|
284929
|
-
});
|
|
284930
|
-
if (!response.ok) {
|
|
284931
|
-
const message = await readNativeHostBridgeError(response);
|
|
284932
|
-
throw new Error(`Native browser host bridge request failed: ${response.status} ${message}`);
|
|
284933
|
-
}
|
|
284934
|
-
return (await response.json()).result;
|
|
284935
|
-
};
|
|
284936
|
-
const subscribe = (input, callback) => {
|
|
284937
|
-
const abortController = new AbortController();
|
|
284938
|
-
const readStream = async () => {
|
|
284939
|
-
if (!options.fetch) {
|
|
284940
|
-
await subscribeToNativeHostBridgeEventsViaNodeHttp({
|
|
284941
|
-
abortSignal: abortController.signal,
|
|
284942
|
-
callback,
|
|
284943
|
-
input,
|
|
284944
|
-
options
|
|
284945
|
-
});
|
|
284946
|
-
return;
|
|
284947
|
-
}
|
|
284948
|
-
const response = await fetchImpl(nativeHostBridgeEventsUrl(options.baseUrl, input), {
|
|
284949
|
-
headers: { authorization: `Bearer ${options.token}` },
|
|
284950
|
-
signal: abortController.signal
|
|
284951
|
-
});
|
|
284952
|
-
if (!response.ok) {
|
|
284953
|
-
const message = await readNativeHostBridgeError(response);
|
|
284954
|
-
throw new Error(`Native browser host bridge event stream failed: ${response.status} ${message}`);
|
|
284955
|
-
}
|
|
284956
|
-
const reader = response.body?.getReader();
|
|
284957
|
-
if (!reader) throw new Error("Native browser host bridge event stream is unavailable.");
|
|
284958
|
-
const decoder = new TextDecoder();
|
|
284959
|
-
let buffer = "";
|
|
284960
|
-
while (!abortController.signal.aborted) {
|
|
284961
|
-
const { done, value } = await reader.read();
|
|
284962
|
-
if (done) return;
|
|
284963
|
-
buffer = drainNativeHostBridgeNdjsonBuffer(buffer + decoder.decode(value, { stream: true }), callback);
|
|
284964
|
-
}
|
|
284965
|
-
};
|
|
284966
|
-
(async () => {
|
|
284967
|
-
let attempt = 0;
|
|
284968
|
-
while (!abortController.signal.aborted) {
|
|
284969
|
-
try {
|
|
284970
|
-
await readStream();
|
|
284971
|
-
attempt = 0;
|
|
284972
|
-
} catch (error) {
|
|
284973
|
-
if (abortController.signal.aborted) return;
|
|
284974
|
-
console.warn("[browser] native host bridge event stream failed", error);
|
|
284975
|
-
}
|
|
284976
|
-
if (!abortController.signal.aborted) {
|
|
284977
|
-
const delayMs = hostBridgeReconnectDelayMs(attempt, NATIVE_HOST_EVENT_RECONNECT_BASE_MS, NATIVE_HOST_EVENT_RECONNECT_MAX_MS);
|
|
284978
|
-
attempt += 1;
|
|
284979
|
-
await abortableDelay(delayMs, abortController.signal);
|
|
284980
|
-
}
|
|
284981
|
-
}
|
|
284982
|
-
})();
|
|
284983
|
-
return () => {
|
|
284984
|
-
abortController.abort();
|
|
284985
|
-
};
|
|
284986
|
-
};
|
|
284987
|
-
return {
|
|
284988
|
-
closeSession: (input = {}) => request("closeSession", input),
|
|
284989
|
-
command: (input) => request("command", input),
|
|
284990
|
-
getSession: (input = {}) => request("getSession", input),
|
|
284991
|
-
listSessions: (input = {}) => request("listSessions", input),
|
|
284992
|
-
onEvent: subscribe,
|
|
284993
|
-
openSession: (input = {}) => request("openSession", input),
|
|
284994
|
-
subscribe: async (input, callback) => subscribe(input, callback)
|
|
284995
|
-
};
|
|
284996
|
-
}
|
|
284997
284388
|
function toHostCommand(command) {
|
|
284998
284389
|
switch (command.type) {
|
|
284999
284390
|
case "activateTab": return {
|
|
@@ -285659,70 +285050,100 @@ const AgentBrowserManagerLive = effect(BrowserManager, gen(function* () {
|
|
|
285659
285050
|
yield* addFinalizer$2(() => promise(() => displayTaskHoldManager?.releaseAll() ?? Promise.resolve()));
|
|
285660
285051
|
const baseBackendOptions = displayCaptureRuntime.backendOptions;
|
|
285661
285052
|
const sessionInitialUrls = /* @__PURE__ */ new Map();
|
|
285662
|
-
const
|
|
285663
|
-
|
|
285664
|
-
|
|
285665
|
-
|
|
285666
|
-
|
|
285667
|
-
|
|
285668
|
-
|
|
285669
|
-
|
|
285670
|
-
|
|
285671
|
-
|
|
285672
|
-
|
|
285673
|
-
|
|
285674
|
-
|
|
285675
|
-
|
|
285676
|
-
|
|
285677
|
-
|
|
285678
|
-
|
|
285679
|
-
|
|
285680
|
-
|
|
285681
|
-
|
|
285682
|
-
|
|
285683
|
-
|
|
285684
|
-
runtime
|
|
285685
|
-
|
|
285686
|
-
|
|
285687
|
-
|
|
285688
|
-
|
|
285689
|
-
|
|
285690
|
-
|
|
285691
|
-
|
|
285692
|
-
|
|
285693
|
-
|
|
285694
|
-
|
|
285695
|
-
|
|
285696
|
-
|
|
285697
|
-
|
|
285698
|
-
|
|
285699
|
-
|
|
285700
|
-
|
|
285701
|
-
|
|
285053
|
+
const reaperContext = yield* context();
|
|
285054
|
+
let runtimeBuild = null;
|
|
285055
|
+
const lazyDisposers = [];
|
|
285056
|
+
const buildPlaywrightRuntime = async () => {
|
|
285057
|
+
const { PlaywrightBackend } = await import("./playwright-backend-DVQOhqRO.mjs");
|
|
285058
|
+
const runtime = createAgentBrowserRuntime({
|
|
285059
|
+
backends: { [DEFAULT_AGENT_BROWSER_ID]: createForgeAgentBrowserPlaywrightBackend(PlaywrightBackend, {
|
|
285060
|
+
...browserBackendOptionsForSession({
|
|
285061
|
+
baseOptions: baseBackendOptions,
|
|
285062
|
+
sessionId: "default"
|
|
285063
|
+
}),
|
|
285064
|
+
name: "Forge Agent Browser"
|
|
285065
|
+
}) },
|
|
285066
|
+
backendFactory: (input) => createForgeAgentBrowserPlaywrightBackend(PlaywrightBackend, {
|
|
285067
|
+
...browserBackendOptionsForSession({
|
|
285068
|
+
baseOptions: baseBackendOptions,
|
|
285069
|
+
initialUrl: sessionInitialUrls.get(input.sessionId),
|
|
285070
|
+
sessionId: input.sessionId
|
|
285071
|
+
}),
|
|
285072
|
+
name: `Forge Agent Browser ${input.sessionId}`
|
|
285073
|
+
})
|
|
285074
|
+
});
|
|
285075
|
+
lazyDisposers.push(() => runtime.close());
|
|
285076
|
+
const hostBridge = createHostBrowserBridge({
|
|
285077
|
+
browserId: DEFAULT_AGENT_BROWSER_ID,
|
|
285078
|
+
closeTabsOnSessionClose: false,
|
|
285079
|
+
defaultViewport: DEFAULT_AGENT_BROWSER_VIEWPORT,
|
|
285080
|
+
runtime,
|
|
285081
|
+
tabLifecycle: {
|
|
285082
|
+
activateNextTabOnClose: true,
|
|
285083
|
+
createFallbackTabOnLastClose: true,
|
|
285084
|
+
fallbackUrl: DEFAULT_URL
|
|
285085
|
+
}
|
|
285086
|
+
});
|
|
285087
|
+
const reaperConfig = browserOrphanReaperConfigFromEnv(process.env, AGENT_BROWSER_PROFILE_ROOT);
|
|
285088
|
+
if (reaperConfig.enabled && process.platform !== "win32") {
|
|
285089
|
+
const reaper = createBrowserOrphanReaper(createSystemBrowserOrphanReaperDeps({
|
|
285090
|
+
profileRoot: AGENT_BROWSER_PROFILE_ROOT,
|
|
285091
|
+
listSessions: () => hostBridge.listSessions(),
|
|
285092
|
+
closeSession: async (sessionId) => {
|
|
285093
|
+
await hostBridge.closeSession({ sessionId: BrowserSessionId.make(sessionId) });
|
|
285094
|
+
}
|
|
285095
|
+
}), reaperConfig);
|
|
285096
|
+
const runReaperFork = runForkWith(reaperContext);
|
|
285097
|
+
const reaperInterval = setInterval(() => {
|
|
285098
|
+
runReaperFork(reaper.sweep);
|
|
285099
|
+
}, reaperConfig.intervalMs);
|
|
285100
|
+
reaperInterval.unref?.();
|
|
285101
|
+
lazyDisposers.push(() => clearInterval(reaperInterval));
|
|
285702
285102
|
runReaperFork(reaper.sweep);
|
|
285703
|
-
}
|
|
285704
|
-
|
|
285705
|
-
|
|
285706
|
-
|
|
285707
|
-
|
|
285708
|
-
|
|
285709
|
-
|
|
285710
|
-
|
|
285711
|
-
|
|
285712
|
-
|
|
285713
|
-
|
|
285714
|
-
|
|
285715
|
-
|
|
285716
|
-
|
|
285717
|
-
|
|
285718
|
-
|
|
285719
|
-
|
|
285720
|
-
|
|
285721
|
-
|
|
285722
|
-
|
|
285103
|
+
}
|
|
285104
|
+
return createAgentBrowserHostBridgeManager(hostBridge, {
|
|
285105
|
+
display: (snapshot) => agentBrowserDisplayForRuntimeMode({
|
|
285106
|
+
mode: serverConfig.mode,
|
|
285107
|
+
iceServers: serverConfig.browserWebRtcIceServerResolver.getCachedIceServers().length > 0 ? serverConfig.browserWebRtcIceServerResolver.getCachedIceServers() : serverConfig.browserWebRtcIceServers,
|
|
285108
|
+
requiresRelay: requiresWebRtcRelay,
|
|
285109
|
+
viewport: snapshot.viewport
|
|
285110
|
+
}),
|
|
285111
|
+
displayIceServers: serverConfig.browserWebRtcIceServers,
|
|
285112
|
+
resolveDisplayIceServers: serverConfig.browserWebRtcIceServerResolver.resolveIceServers,
|
|
285113
|
+
displayPeers,
|
|
285114
|
+
prepareRuntimeSession: (input) => {
|
|
285115
|
+
sessionInitialUrls.set(input.sessionId, input.initialUrl);
|
|
285116
|
+
},
|
|
285117
|
+
forgetRuntimeSession: (input) => {
|
|
285118
|
+
sessionInitialUrls.delete(input.sessionId);
|
|
285119
|
+
},
|
|
285120
|
+
requiresWebRtcRelay
|
|
285121
|
+
});
|
|
285122
|
+
};
|
|
285123
|
+
yield* addFinalizer$2(() => promise(async () => {
|
|
285124
|
+
for (const dispose of lazyDisposers.toReversed()) await dispose();
|
|
285125
|
+
}).pipe(orDie));
|
|
285126
|
+
const ensurePlaywrightRuntime = () => tryPromise({
|
|
285127
|
+
try: () => {
|
|
285128
|
+
runtimeBuild ??= buildPlaywrightRuntime();
|
|
285129
|
+
return runtimeBuild;
|
|
285723
285130
|
},
|
|
285724
|
-
|
|
285131
|
+
catch: (cause) => {
|
|
285132
|
+
runtimeBuild = null;
|
|
285133
|
+
return toBrowserError(cause, "Browser backend could not be loaded. Browser packages load on first browser use and must be provisioned on this runtime.");
|
|
285134
|
+
}
|
|
285725
285135
|
});
|
|
285136
|
+
return {
|
|
285137
|
+
openSession: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.openSession(input)),
|
|
285138
|
+
closeSession: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.closeSession(input)),
|
|
285139
|
+
clearBrowsingData: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.clearBrowsingData(input)),
|
|
285140
|
+
getSession: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.getSession(input)),
|
|
285141
|
+
listSessions: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.listSessions(input)),
|
|
285142
|
+
command: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.command(input)),
|
|
285143
|
+
attachDisplay: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.attachDisplay(input)),
|
|
285144
|
+
addDisplayIceCandidate: (input) => flatMap(ensurePlaywrightRuntime(), (m) => m.addDisplayIceCandidate(input)),
|
|
285145
|
+
subscribe: (input, listener) => flatMap(orDie(ensurePlaywrightRuntime()), (m) => m.subscribe(input, listener))
|
|
285146
|
+
};
|
|
285726
285147
|
}));
|
|
285727
285148
|
//#endregion
|
|
285728
285149
|
//#region src/devTunnel/http.ts
|
|
@@ -297678,7 +297099,7 @@ function resolveBuildCommitFromEnv(env) {
|
|
|
297678
297099
|
* environment descriptor down instead of reporting an honest "unknown".
|
|
297679
297100
|
*/
|
|
297680
297101
|
function readBakedBuildCommit() {
|
|
297681
|
-
return "
|
|
297102
|
+
return "e0ef2b5174f2f50934814b1865cabaa9c7de0ce7";
|
|
297682
297103
|
}
|
|
297683
297104
|
async function resolveServerBuildCommit(input) {
|
|
297684
297105
|
if (isFullCommitSha(input.baked)) return input.baked;
|
|
@@ -321180,13 +320601,13 @@ const gitUrlCloneRouteLayer = add$1("POST", "/api/cloud/git/clone-url", gen(func
|
|
|
321180
320601
|
//#endregion
|
|
321181
320602
|
//#region src/server.ts
|
|
321182
320603
|
const PtyAdapterLive = unwrap(gen(function* () {
|
|
321183
|
-
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunPTY-
|
|
321184
|
-
else return (yield* promise(() => import("./NodePTY-
|
|
320604
|
+
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunPTY-Csgwhbi5.mjs"))).layer;
|
|
320605
|
+
else return (yield* promise(() => import("./NodePTY-DgXWLtWp.mjs"))).layer;
|
|
321185
320606
|
}));
|
|
321186
320607
|
const HttpServerLive = unwrap(gen(function* () {
|
|
321187
320608
|
const config = yield* ServerConfig;
|
|
321188
|
-
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunHttpServer-
|
|
321189
|
-
const [NodeHttpServer, NodeHttp] = yield* all([promise(() => import("./NodeHttpServer-
|
|
320609
|
+
if (typeof Bun !== "undefined") return (yield* promise(() => import("./BunHttpServer-DjilmGOM.mjs"))).layer(bunHttpServerOptions(config));
|
|
320610
|
+
const [NodeHttpServer, NodeHttp] = yield* all([promise(() => import("./NodeHttpServer-Ds3Gp1Gp.mjs")), promise(() => import("node:http"))]);
|
|
321190
320611
|
return NodeHttpServer.layer(NodeHttp.createServer, {
|
|
321191
320612
|
host: config.host,
|
|
321192
320613
|
port: config.port
|
|
@@ -321194,7 +320615,7 @@ const HttpServerLive = unwrap(gen(function* () {
|
|
|
321194
320615
|
}));
|
|
321195
320616
|
const PlatformServicesLive = unwrap(gen(function* () {
|
|
321196
320617
|
if (typeof Bun !== "undefined") {
|
|
321197
|
-
const { layer } = yield* promise(() => import("./BunServices-
|
|
320618
|
+
const { layer } = yield* promise(() => import("./BunServices-BZKzHdrG.mjs"));
|
|
321198
320619
|
return layer;
|
|
321199
320620
|
} else {
|
|
321200
320621
|
const { layer } = yield* promise(() => import("./NodeServices-D3IxOzHl.mjs").then((n) => n.t));
|
|
@@ -322192,7 +321613,7 @@ const connectLoginCommand = make$34("login", {
|
|
|
322192
321613
|
})).json();
|
|
322193
321614
|
},
|
|
322194
321615
|
openBrowser: async (url) => {
|
|
322195
|
-
const open = (await import("./open-
|
|
321616
|
+
const open = (await import("./open-2-reBrpv.mjs")).default;
|
|
322196
321617
|
await open(url);
|
|
322197
321618
|
return true;
|
|
322198
321619
|
},
|