@trusty-squire/mcp 1.0.10-rc.2 → 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.
- package/dist/bot/browser.js +32 -32
- package/dist/bot/browser.js.map +1 -1
- package/dist/bot/credential-extraction-flow.js +1 -1
- package/dist/bot/credential-extraction-flow.js.map +1 -1
- package/dist/bot/credential-text.d.ts.map +1 -1
- package/dist/bot/credential-text.js +2 -3
- package/dist/bot/credential-text.js.map +1 -1
- package/dist/bot/email-verification.d.ts.map +1 -1
- package/dist/bot/email-verification.js +2 -3
- package/dist/bot/email-verification.js.map +1 -1
- package/dist/bot/extraction.d.ts.map +1 -1
- package/dist/bot/extraction.js +2 -3
- package/dist/bot/extraction.js.map +1 -1
- package/dist/bot/index.d.ts.map +1 -1
- package/dist/bot/index.js +1 -2
- package/dist/bot/index.js.map +1 -1
- package/dist/bot/oauth-detect.d.ts.map +1 -1
- package/dist/bot/oauth-detect.js +2 -3
- package/dist/bot/oauth-detect.js.map +1 -1
- package/dist/bot/oauth-providers.js +1 -1
- package/dist/bot/oauth-providers.js.map +1 -1
- package/dist/bot/promote-to-skill.js +2 -2
- package/dist/bot/promote-to-skill.js.map +1 -1
- package/dist/bot/provision-session.d.ts +4 -11
- package/dist/bot/provision-session.d.ts.map +1 -1
- package/dist/bot/provision-session.js +12 -36
- package/dist/bot/provision-session.js.map +1 -1
- package/dist/bot/provision-types.js +2 -2
- package/dist/bot/provision-types.js.map +1 -1
- package/dist/tools/provision-drive.d.ts +3 -6
- package/dist/tools/provision-drive.d.ts.map +1 -1
- package/dist/tools/provision-drive.js +17 -28
- package/dist/tools/provision-drive.js.map +1 -1
- package/package.json +1 -1
package/dist/bot/browser.js
CHANGED
|
@@ -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
|
|
23
|
-
//
|
|
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(`[
|
|
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(`[
|
|
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("[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
884
|
+
console.error(`[operator] no DISPLAY — spawned Xvfb at ${this.xvfb.display} for headed Chrome`);
|
|
885
885
|
}
|
|
886
886
|
catch (err) {
|
|
887
|
-
console.error(`[
|
|
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(`[
|
|
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("[
|
|
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("[
|
|
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("[
|
|
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(`[
|
|
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(`[
|
|
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("[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
1371
|
+
console.error(`[operator] routing through residential proxy ` +
|
|
1372
1372
|
`(asn=${asnClass}${forceAlways ? ", forced" : ""})`);
|
|
1373
1373
|
return proxy;
|
|
1374
1374
|
}
|
|
1375
|
-
console.error(`[
|
|
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(`[
|
|
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
|
|
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("[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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(`[
|
|
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
|
|
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
|