@cmmd-center/forge 0.13.29 → 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.
Files changed (44) hide show
  1. package/dist/{BunHttpServer-C0oPP_3A.cjs → BunHttpServer-CXndtc1j.cjs} +2 -2
  2. package/dist/{BunHttpServer-FbbQmsl_.mjs → BunHttpServer-DjilmGOM.mjs} +2 -2
  3. package/dist/{BunPTY-uyreNRGp.cjs → BunPTY-BiTlUj63.cjs} +1 -1
  4. package/dist/{BunPTY-DkAIzLIx.mjs → BunPTY-Csgwhbi5.mjs} +1 -1
  5. package/dist/{BunServices-DC7nhA3w.mjs → BunServices-BZKzHdrG.mjs} +1 -1
  6. package/dist/{BunServices-DkenwD7S.cjs → BunServices-DsWG7VM1.cjs} +1 -1
  7. package/dist/{NodeHttpServer-Cjd3bFrD.cjs → NodeHttpServer-B4dCKqYY.cjs} +1 -1
  8. package/dist/{NodeHttpServer-BJ4l15f-.mjs → NodeHttpServer-Ds3Gp1Gp.mjs} +1 -1
  9. package/dist/{NodePTY-BehazUMi.cjs → NodePTY-BJ7874MO.cjs} +1 -1
  10. package/dist/{NodePTY-BhezYy9H.mjs → NodePTY-DgXWLtWp.mjs} +1 -1
  11. package/dist/{NodeSqliteClient-CfsdC3AB.cjs → NodeSqliteClient-CPsJxxdD.cjs} +1 -1
  12. package/dist/{NodeSqliteClient-md8xd9hY.mjs → NodeSqliteClient-D29w60zZ.mjs} +1 -1
  13. package/dist/{SqliteClient-BKB695RF.mjs → SqliteClient-Bgo_s5sA.mjs} +1 -1
  14. package/dist/{SqliteClient-O1ABIngw.cjs → SqliteClient-k0pbfeIC.cjs} +1 -1
  15. package/dist/bin.cjs +432 -1012
  16. package/dist/bin.mjs +430 -1009
  17. package/dist/client/assets/{DiffPanel-CsYeFcEd.js → DiffPanel-u3cympMJ.js} +2 -2
  18. package/dist/client/assets/{DiffPanel.logic-BhrQueD8.js → DiffPanel.logic-Im6HMxhw.js} +2 -2
  19. package/dist/client/assets/{DiffPanelShell-CssAtWUC.js → DiffPanelShell-BckZpJGo.js} +3 -3
  20. package/dist/client/assets/{DiffWorkerPoolProvider-C0iUCn9m.js → DiffWorkerPoolProvider-Bwjf7Bmf.js} +2 -2
  21. package/dist/client/assets/{PullRequestCodePanel-O-XZJVnK.js → PullRequestCodePanel-VADCfzOQ.js} +2 -2
  22. package/dist/client/assets/{Virtualizer-Z2t67-w7.js → Virtualizer-Dp4FFzsC.js} +2 -2
  23. package/dist/client/assets/{index-AMVPSS6N.js → index-CiD_w5sq.js} +6 -6
  24. package/dist/client/index.html +4 -4
  25. package/dist/{execAsync-BUcaFQ1D.cjs → execAsync--H9ZZOiC.cjs} +1 -1
  26. package/dist/{execAsync-BNNdR88o.mjs → execAsync-BJ4g1UuR.mjs} +1 -1
  27. package/dist/forge-build.json +1 -1
  28. package/dist/{getMachineId-bsd-3FzKrfVS.cjs → getMachineId-bsd-CJJWgsvW.cjs} +2 -2
  29. package/dist/{getMachineId-bsd-BuYwT36r.mjs → getMachineId-bsd-CvzjzhCJ.mjs} +2 -2
  30. package/dist/{getMachineId-darwin-RZKhGQ6C.mjs → getMachineId-darwin-BkjZ6NK7.mjs} +2 -2
  31. package/dist/{getMachineId-darwin-J2wNbebX.cjs → getMachineId-darwin-hZeIAq-t.cjs} +2 -2
  32. package/dist/{getMachineId-linux-BDLTrARB.cjs → getMachineId-linux-B4Pn5gp9.cjs} +1 -1
  33. package/dist/{getMachineId-linux-D5HSP0rH.mjs → getMachineId-linux-BaBxzaf3.mjs} +1 -1
  34. package/dist/{getMachineId-unsupported-DRh5MFwr.cjs → getMachineId-unsupported-B3jtoOL0.cjs} +1 -1
  35. package/dist/{getMachineId-unsupported-IaplPZnC.mjs → getMachineId-unsupported-EhCzrOph.mjs} +1 -1
  36. package/dist/{getMachineId-win-D220ursp.mjs → getMachineId-win-BFwtIsaZ.mjs} +2 -2
  37. package/dist/{getMachineId-win-BA8dHcjg.cjs → getMachineId-win-Bb4lJE8e.cjs} +2 -2
  38. package/dist/{open-D8mGyWmt.mjs → open-2-reBrpv.mjs} +1 -1
  39. package/dist/{open-BAsPVCWX.cjs → open-CghsF25U.cjs} +1 -1
  40. package/dist/playwright-backend-BONxTCSA.cjs +643 -0
  41. package/dist/playwright-backend-DVQOhqRO.mjs +642 -0
  42. package/dist/settle-B6Rn65UV.cjs +28 -0
  43. package/dist/settle-BJcmpbvq.mjs +23 -0
  44. 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";
@@ -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";
@@ -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-RZKhGQ6C.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
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-D5HSP0rH.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
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-BuYwT36r.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
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-D220ursp.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
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-IaplPZnC.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
52912
+ getMachineIdImpl = (await import("./getMachineId-unsupported-EhCzrOph.mjs").then((m) => /* @__PURE__ */ __toESM(m.default))).getMachineId;
52913
52913
  break;
52914
52914
  }
52915
52915
  return getMachineIdImpl();
@@ -65937,7 +65937,7 @@ function normalizeNumberish(value) {
65937
65937
  }
65938
65938
  //#endregion
65939
65939
  //#region package.json
65940
- var version$1 = "0.13.29";
65940
+ var version$1 = "0.13.30";
65941
65941
  //#endregion
65942
65942
  //#region src/sentry.ts
65943
65943
  const SERVER_APP_NAME = "forge-server";
@@ -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-D8mGyWmt.mjs"),
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-BKB695RF.mjs"),
118057
- node: () => import("./NodeSqliteClient-md8xd9hY.mjs")
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"];
@@ -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$1(action)
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$1(action)
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$1(action),
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$1(action),
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$1(action),
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$1(action),
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$1(action),
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$1(action) {
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
  /**
@@ -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
- var ForgeAgentBrowserPlaywrightBackend = class extends PlaywrightBackend {
284684
- async close() {
284685
- await closeAgentBrowserBackendWithTimeout(() => super.close());
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 runtime = createAgentBrowserRuntime({
285663
- backends: { [DEFAULT_AGENT_BROWSER_ID]: new ForgeAgentBrowserPlaywrightBackend({
285664
- ...browserBackendOptionsForSession({
285665
- baseOptions: baseBackendOptions,
285666
- sessionId: "default"
285667
- }),
285668
- name: "Forge Agent Browser"
285669
- }) },
285670
- backendFactory: (input) => new ForgeAgentBrowserPlaywrightBackend({
285671
- ...browserBackendOptionsForSession({
285672
- baseOptions: baseBackendOptions,
285673
- initialUrl: sessionInitialUrls.get(input.sessionId),
285674
- sessionId: input.sessionId
285675
- }),
285676
- name: `Forge Agent Browser ${input.sessionId}`
285677
- })
285678
- });
285679
- yield* addFinalizer$2(() => promise(() => runtime.close()).pipe(orDie));
285680
- const hostBridge = createHostBrowserBridge({
285681
- browserId: DEFAULT_AGENT_BROWSER_ID,
285682
- closeTabsOnSessionClose: false,
285683
- defaultViewport: DEFAULT_AGENT_BROWSER_VIEWPORT,
285684
- runtime,
285685
- tabLifecycle: {
285686
- activateNextTabOnClose: true,
285687
- createFallbackTabOnLastClose: true,
285688
- fallbackUrl: DEFAULT_URL
285689
- }
285690
- });
285691
- const reaperConfig = browserOrphanReaperConfigFromEnv(process.env, AGENT_BROWSER_PROFILE_ROOT);
285692
- if (reaperConfig.enabled && process.platform !== "win32") {
285693
- const reaper = createBrowserOrphanReaper(createSystemBrowserOrphanReaperDeps({
285694
- profileRoot: AGENT_BROWSER_PROFILE_ROOT,
285695
- listSessions: () => hostBridge.listSessions(),
285696
- closeSession: async (sessionId) => {
285697
- await hostBridge.closeSession({ sessionId: BrowserSessionId.make(sessionId) });
285698
- }
285699
- }), reaperConfig);
285700
- const runReaperFork = runForkWith(yield* context());
285701
- const reaperInterval = setInterval(() => {
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
- }, reaperConfig.intervalMs);
285704
- reaperInterval.unref?.();
285705
- yield* addFinalizer$2(() => sync$1(() => clearInterval(reaperInterval)));
285706
- runReaperFork(reaper.sweep);
285707
- }
285708
- return createAgentBrowserHostBridgeManager(hostBridge, {
285709
- display: (snapshot) => agentBrowserDisplayForRuntimeMode({
285710
- mode: serverConfig.mode,
285711
- iceServers: serverConfig.browserWebRtcIceServerResolver.getCachedIceServers().length > 0 ? serverConfig.browserWebRtcIceServerResolver.getCachedIceServers() : serverConfig.browserWebRtcIceServers,
285712
- requiresRelay: requiresWebRtcRelay,
285713
- viewport: snapshot.viewport
285714
- }),
285715
- displayIceServers: serverConfig.browserWebRtcIceServers,
285716
- resolveDisplayIceServers: serverConfig.browserWebRtcIceServerResolver.resolveIceServers,
285717
- displayPeers,
285718
- prepareRuntimeSession: (input) => {
285719
- sessionInitialUrls.set(input.sessionId, input.initialUrl);
285720
- },
285721
- forgetRuntimeSession: (input) => {
285722
- sessionInitialUrls.delete(input.sessionId);
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
- requiresWebRtcRelay
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 "3aa3aed2accf8eb5e70a159243d778df7c98a4be";
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-DkAIzLIx.mjs"))).layer;
321184
- else return (yield* promise(() => import("./NodePTY-BhezYy9H.mjs"))).layer;
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-FbbQmsl_.mjs"))).layer(bunHttpServerOptions(config));
321189
- const [NodeHttpServer, NodeHttp] = yield* all([promise(() => import("./NodeHttpServer-BJ4l15f-.mjs")), promise(() => import("node:http"))]);
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-DC7nhA3w.mjs"));
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-D8mGyWmt.mjs")).default;
321616
+ const open = (await import("./open-2-reBrpv.mjs")).default;
322196
321617
  await open(url);
322197
321618
  return true;
322198
321619
  },