@trusty-squire/mcp 1.0.10-rc.3 → 1.0.10

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.
@@ -19,8 +19,8 @@
19
19
  // Together with the user's residential IP (the bot runs on user
20
20
  // machines, not on Fly), these are sufficient for invisible-mode
21
21
  // Turnstile/reCAPTCHA-v3 scoring on most SaaS signups. Visible-mode
22
- // captchas still need the click-and-wait pattern documented in
23
- // agent.ts.
22
+ // captchas still need the click-and-wait pattern (the Tier 2 captcha
23
+ // gate).
24
24
  import { chromium as baseChromium } from "playwright";
25
25
  import { createRequire } from "node:module";
26
26
  import { Socket, createServer } from "node:net";
@@ -103,7 +103,7 @@ function getChromium() {
103
103
  // Fall back to vanilla playwright if stealth (or the rebrowser fork)
104
104
  // isn't installed. The bot still works, it's just easier to
105
105
  // fingerprint as a bot — and the A/B tag stays truthfully "baseline".
106
- console.warn(`[universal-bot] hardened launcher unavailable, falling back to vanilla chromium: ${err instanceof Error ? err.message : String(err)}`);
106
+ console.warn(`[operator] hardened launcher unavailable, falling back to vanilla chromium: ${err instanceof Error ? err.message : String(err)}`);
107
107
  cachedChromium = baseChromium;
108
108
  activeStealthProfile = "baseline";
109
109
  }
@@ -492,7 +492,7 @@ function reapOrphanedVerifyBrowsersOnce() {
492
492
  }
493
493
  if (pids.length === 0)
494
494
  return;
495
- console.error(`[universal-bot] reaping ${pids.length} orphaned verify Chrome process(es)`);
495
+ console.error(`[operator] reaping ${pids.length} orphaned verify Chrome process(es)`);
496
496
  for (const pid of pids)
497
497
  killPid(pid, "SIGTERM");
498
498
  setTimeout(() => {
@@ -794,7 +794,7 @@ export class BrowserController {
794
794
  // Routing race / already-handled — never let a decision crash nav.
795
795
  }
796
796
  });
797
- console.error("[universal-bot] resource blocking ON (image/media/font + analytics aborted; captcha/CSS/JS allowed)");
797
+ console.error("[operator] resource blocking ON (image/media/font + analytics aborted; captcha/CSS/JS allowed)");
798
798
  }
799
799
  async start() {
800
800
  reapOrphanedVerifyBrowsersOnce();
@@ -804,7 +804,7 @@ export class BrowserController {
804
804
  this.proxyServer = proxy?.server ?? null;
805
805
  // Stderr so the MCP stdio transport's framing stays clean (the
806
806
  // module's existing logging convention).
807
- console.error(`[universal-bot] launching browser channel=${channel ?? "bundled-chromium"} ` +
807
+ console.error(`[operator] launching browser channel=${channel ?? "bundled-chromium"} ` +
808
808
  `proxy=${proxy?.server ?? "direct"}`);
809
809
  // Remote-CDP mode (BOT_CDP_ENDPOINT): the browser runs on a REMOTE host
810
810
  // (e.g. a Mac with a real GPU + residential egress) and we attach over CDP
@@ -817,7 +817,7 @@ export class BrowserController {
817
817
  // fingerprint, which is the whole point of this path.
818
818
  const remoteMode = (process.env.BOT_CDP_ENDPOINT ?? "").trim().length > 0;
819
819
  if (remoteMode) {
820
- console.error(`[universal-bot] REMOTE-CDP mode — attaching to ${(process.env.BOT_CDP_ENDPOINT ?? "").trim()} ` +
820
+ console.error(`[operator] REMOTE-CDP mode — attaching to ${(process.env.BOT_CDP_ENDPOINT ?? "").trim()} ` +
821
821
  `(real-host GPU + egress; local fingerprint spoof + Xvfb DISABLED)`);
822
822
  }
823
823
  // T3.1: probe where this run's traffic actually exits so the
@@ -828,7 +828,7 @@ export class BrowserController {
828
828
  // remote mode — the remote host's own clock/IP are the authentic truth.
829
829
  const geo = remoteMode ? null : await this.probeEgressGeo(channel, proxy);
830
830
  if (geo !== null) {
831
- console.error(`[universal-bot] egress geo: timezone=${geo.timezoneId}` +
831
+ console.error(`[operator] egress geo: timezone=${geo.timezoneId}` +
832
832
  (geo.geolocation !== undefined
833
833
  ? ` loc=${geo.geolocation.latitude},${geo.geolocation.longitude}`
834
834
  : ""));
@@ -881,17 +881,17 @@ export class BrowserController {
881
881
  chromeEnv = { ...process.env, DISPLAY: this.xvfb.display };
882
882
  chromeHeadless = false;
883
883
  this.launchedMode = "xvfb";
884
- console.error(`[universal-bot] no DISPLAY — spawned Xvfb at ${this.xvfb.display} for headed Chrome`);
884
+ console.error(`[operator] no DISPLAY — spawned Xvfb at ${this.xvfb.display} for headed Chrome`);
885
885
  }
886
886
  catch (err) {
887
- console.error(`[universal-bot] Xvfb failed (${err instanceof Error ? err.message : String(err)}) — ` +
887
+ console.error(`[operator] Xvfb failed (${err instanceof Error ? err.message : String(err)}) — ` +
888
888
  `falling back to true headless; Cloudflare/Stytch-class signups may fail`);
889
889
  chromeHeadless = true;
890
890
  this.launchedMode = "headless";
891
891
  }
892
892
  }
893
893
  else {
894
- console.error(`[universal-bot] no DISPLAY and Xvfb not installed — running true headless. ` +
894
+ console.error(`[operator] no DISPLAY and Xvfb not installed — running true headless. ` +
895
895
  `For Cloudflare/Stytch-class signups install xvfb: apt-get install -y xvfb`);
896
896
  chromeHeadless = true;
897
897
  this.launchedMode = "headless";
@@ -902,7 +902,7 @@ export class BrowserController {
902
902
  // aborts with "Failed to create a ProcessSingleton" and bricks the run.
903
903
  let free = await waitForProfileFree(this.profileDir, {
904
904
  deadlineMs: 120_000,
905
- onWait: () => console.error("[universal-bot] bot Chrome profile is busy with another run — waiting…"),
905
+ onWait: () => console.error("[operator] bot Chrome profile is busy with another run — waiting…"),
906
906
  });
907
907
  if (!free) {
908
908
  // A live-pid holder that never released within the deadline. The
@@ -927,11 +927,11 @@ export class BrowserController {
927
927
  const allowLiveReap = concurrency <= 1;
928
928
  const reaped = allowLiveReap ? reapLeakedProfileHolder(this.profileDir) : false;
929
929
  if (reaped) {
930
- console.error("[universal-bot] reaped a leaked Chrome holding the profile (orphan from an externally-killed run) — retrying");
930
+ console.error("[operator] reaped a leaked Chrome holding the profile (orphan from an externally-killed run) — retrying");
931
931
  free = await waitForProfileFree(this.profileDir, { deadlineMs: 10_000 });
932
932
  }
933
933
  else if (!allowLiveReap) {
934
- console.error("[universal-bot] profile still held after wait; not reaping because HOUSEKEEPER_CONCURRENCY>1");
934
+ console.error("[operator] profile still held after wait; not reaping because HOUSEKEEPER_CONCURRENCY>1");
935
935
  }
936
936
  if (!free) {
937
937
  throw new ProfileBusyError("bot Chrome profile is held by another run (a login or signup); retry shortly");
@@ -983,7 +983,7 @@ export class BrowserController {
983
983
  const useSelfLaunch = selfLaunchBinary !== null && !proxyHasAuth;
984
984
  let context;
985
985
  if (useSelfLaunch && selfLaunchBinary !== null) {
986
- console.error(`[universal-bot] self-launch + connectOverCDP (Turnstile-safe launch) binary=${selfLaunchBinary}`);
986
+ console.error(`[operator] self-launch + connectOverCDP (Turnstile-safe launch) binary=${selfLaunchBinary}`);
987
987
  // Window size matches the display surface so viewport reads as a real
988
988
  // window (no emulated-viewport tell). TZ on the child makes Chrome
989
989
  // report the egress timezone natively.
@@ -1012,12 +1012,12 @@ export class BrowserController {
1012
1012
  }
1013
1013
  }
1014
1014
  catch (err) {
1015
- console.error(`[universal-bot] post-connect context setup partial: ${err instanceof Error ? err.message : String(err)}`);
1015
+ console.error(`[operator] post-connect context setup partial: ${err instanceof Error ? err.message : String(err)}`);
1016
1016
  }
1017
1017
  }
1018
1018
  else {
1019
1019
  if (selfLaunchEnabled() && selfLaunchBinary !== null && proxyHasAuth) {
1020
- console.error("[universal-bot] credentialed proxy → launchPersistentContext (self-launch can't carry proxy auth)");
1020
+ console.error("[operator] credentialed proxy → launchPersistentContext (self-launch can't carry proxy auth)");
1021
1021
  }
1022
1022
  // T3: a PERSISTENT context (the legacy path). The profile dir carries the
1023
1023
  // user's Google session so the OAuth-first path reuses it.
@@ -1290,7 +1290,7 @@ export class BrowserController {
1290
1290
  return parseEgressGeo(await resp.text());
1291
1291
  }
1292
1292
  catch (err) {
1293
- console.error(`[universal-bot] egress geo probe failed — using default ` +
1293
+ console.error(`[operator] egress geo probe failed — using default ` +
1294
1294
  `timezone: ${err instanceof Error ? err.message : String(err)}`);
1295
1295
  return null;
1296
1296
  }
@@ -1312,7 +1312,7 @@ export class BrowserController {
1312
1312
  return parseEgressGeo(body);
1313
1313
  }
1314
1314
  catch (err) {
1315
- console.error(`[universal-bot] egress geo probe failed — using default ` +
1315
+ console.error(`[operator] egress geo probe failed — using default ` +
1316
1316
  `timezone: ${err instanceof Error ? err.message : String(err)}`);
1317
1317
  return null;
1318
1318
  }
@@ -1345,7 +1345,7 @@ export class BrowserController {
1345
1345
  proxy = parseProxyUrl(raw);
1346
1346
  }
1347
1347
  catch (err) {
1348
- console.error(`[universal-bot] UNIVERSAL_BOT_PROXY_URL is malformed — running ` +
1348
+ console.error(`[operator] UNIVERSAL_BOT_PROXY_URL is malformed — running ` +
1349
1349
  `direct: ${err instanceof Error ? err.message : String(err)}`);
1350
1350
  return null;
1351
1351
  }
@@ -1363,16 +1363,16 @@ export class BrowserController {
1363
1363
  // datacenter IPs, instead of dying entirely. Self-healing > silent stall.
1364
1364
  const reachable = await isProxyReachable(proxy.server);
1365
1365
  if (!reachable) {
1366
- console.error(`[universal-bot] proxy ${proxy.server} is UNREACHABLE — falling back to ` +
1366
+ console.error(`[operator] proxy ${proxy.server} is UNREACHABLE — falling back to ` +
1367
1367
  `DIRECT egress (datacenter IP; anti-bot services may block it, but far ` +
1368
1368
  `better than every navigation timing out)`);
1369
1369
  return null;
1370
1370
  }
1371
- console.error(`[universal-bot] routing through residential proxy ` +
1371
+ console.error(`[operator] routing through residential proxy ` +
1372
1372
  `(asn=${asnClass}${forceAlways ? ", forced" : ""})`);
1373
1373
  return proxy;
1374
1374
  }
1375
- console.error(`[universal-bot] direct connection (asn=${asnClass}) — proxy ` +
1375
+ console.error(`[operator] direct connection (asn=${asnClass}) — proxy ` +
1376
1376
  `configured but not needed for this network`);
1377
1377
  return null;
1378
1378
  }
@@ -1592,7 +1592,7 @@ export class BrowserController {
1592
1592
  // Any step in the chain failing leaves us at *some* page (the
1593
1593
  // search results, the marketing site, an error page) — that's
1594
1594
  // still better than a cold landing on /sign_up. Log and proceed.
1595
- console.error(`[universal-bot] referrer-chain prewarm partial failure (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
1595
+ console.error(`[operator] referrer-chain prewarm partial failure (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
1596
1596
  }
1597
1597
  }
1598
1598
  async type(selector, text) {
@@ -4925,7 +4925,7 @@ export class BrowserController {
4925
4925
  // isMasked: true if the value looks like a redacted display
4926
4926
  // (••••, ****, contains "•" or runs of "*") }
4927
4927
  //
4928
- // The caller (agent.ts extractAllLabeledCandidates path) maps label
4928
+ // The caller maps label
4929
4929
  // text to canonical credential keys using the same vocabulary the
4930
4930
  // Phase E parser uses.
4931
4931
  async extractLabeledCredentialCandidates() {
@@ -6611,10 +6611,10 @@ export class BrowserController {
6611
6611
  try {
6612
6612
  cdp = await this.context.newCDPSession(this.page);
6613
6613
  await cdp.send("FedCm.enable", { disableRejectionDelay: true });
6614
- console.error("[universal-bot] FedCm.enable ok — listening for dialogShown");
6614
+ console.error("[operator] FedCm.enable ok — listening for dialogShown");
6615
6615
  cdp.on("FedCm.dialogShown", (ev) => {
6616
6616
  const e = ev;
6617
- console.error(`[universal-bot] FedCm.dialogShown type=${e.dialogType ?? "?"} accounts=${Array.isArray(e.accounts) ? e.accounts.length : "?"}`);
6617
+ console.error(`[operator] FedCm.dialogShown type=${e.dialogType ?? "?"} accounts=${Array.isArray(e.accounts) ? e.accounts.length : "?"}`);
6618
6618
  const dialogId = e.dialogId;
6619
6619
  if (dialogId === undefined)
6620
6620
  return;
@@ -6665,7 +6665,7 @@ export class BrowserController {
6665
6665
  }
6666
6666
  catch (err) {
6667
6667
  cdp = null; // FedCm domain unavailable — the popup path still works
6668
- console.error(`[universal-bot] FedCm.enable failed (${err instanceof Error ? err.message : String(err)}) — FedCM path disabled, relying on popup`);
6668
+ console.error(`[operator] FedCm.enable failed (${err instanceof Error ? err.message : String(err)}) — FedCM path disabled, relying on popup`);
6669
6669
  }
6670
6670
  const popupPromise = this.context
6671
6671
  .waitForEvent("page", { timeout: timeoutMs })
@@ -6739,7 +6739,7 @@ export class BrowserController {
6739
6739
  }
6740
6740
  return { ok: true, via: "fedcm" };
6741
6741
  }
6742
- console.error(`[universal-bot] GSI resolved via none — fedcmEnabled=${cdp !== null} ` +
6742
+ console.error(`[operator] GSI resolved via none — fedcmEnabled=${cdp !== null} ` +
6743
6743
  `fedcmResolved=${fedcmResolved} pages=${this.context.pages().length}`);
6744
6744
  return { ok: false, via: "none" };
6745
6745
  }
@@ -7082,7 +7082,7 @@ export class BrowserController {
7082
7082
  .filter((t) => t.length > 0);
7083
7083
  })
7084
7084
  .catch(() => []);
7085
- console.error(`[universal-bot] GitHub advanceOAuthConsent failed — visible buttons: ` +
7085
+ console.error(`[operator] GitHub advanceOAuthConsent failed — visible buttons: ` +
7086
7086
  `${seen.length === 0 ? "<none>" : seen.map((s) => JSON.stringify(s)).join(", ")}`);
7087
7087
  return false;
7088
7088
  }
@@ -7165,7 +7165,7 @@ export class BrowserController {
7165
7165
  .filter((t) => t.length > 0);
7166
7166
  })
7167
7167
  .catch(() => []);
7168
- console.error(`[universal-bot] Google advanceOAuthConsent failed — visible buttons: ` +
7168
+ console.error(`[operator] Google advanceOAuthConsent failed — visible buttons: ` +
7169
7169
  `${seen.length === 0 ? "<none>" : seen.map((s) => JSON.stringify(s)).join(", ")}`);
7170
7170
  return false;
7171
7171
  }
@@ -7303,7 +7303,7 @@ function rand(min, max) {
7303
7303
  // button[type=submit] next to the real account-creation button, so a
7304
7304
  // generic selector resolves to several — this picks the right one.
7305
7305
  //
7306
- // Same shape and rationale as agent.ts's pickVerificationLink: a positive
7306
+ // Same shape and rationale as the verification-link picker: a positive
7307
7307
  // score gate so an OAuth-only page (every candidate negative) returns
7308
7308
  // null rather than mis-clicking "Continue with Google".
7309
7309
  // Click disambiguation (regression: #61 weaviate). A bare id selector can