@trusty-squire/mcp 0.8.14 → 0.8.16
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/agent.d.ts +12 -1
- package/dist/bot/agent.d.ts.map +1 -1
- package/dist/bot/agent.js +715 -56
- package/dist/bot/agent.js.map +1 -1
- package/dist/bot/browser.d.ts +2 -2
- package/dist/bot/browser.d.ts.map +1 -1
- package/dist/bot/browser.js +88 -66
- package/dist/bot/browser.js.map +1 -1
- package/dist/bot/promote-to-skill.d.ts +2 -1
- package/dist/bot/promote-to-skill.d.ts.map +1 -1
- package/dist/bot/promote-to-skill.js +26 -0
- package/dist/bot/promote-to-skill.js.map +1 -1
- package/dist/bot/replay-skill.d.ts.map +1 -1
- package/dist/bot/replay-skill.js +237 -32
- package/dist/bot/replay-skill.js.map +1 -1
- package/dist/bot/xvfb.d.ts.map +1 -1
- package/dist/bot/xvfb.js +8 -3
- package/dist/bot/xvfb.js.map +1 -1
- package/dist/install/cli.d.ts +5 -0
- package/dist/install/cli.d.ts.map +1 -1
- package/dist/install/cli.js +33 -8
- package/dist/install/cli.js.map +1 -1
- package/package.json +2 -1
package/dist/bot/browser.d.ts
CHANGED
|
@@ -126,9 +126,9 @@ interface ShadowWalkRoot {
|
|
|
126
126
|
querySelectorAll(selectors: string): ArrayLike<ShadowWalkEl>;
|
|
127
127
|
}
|
|
128
128
|
interface ShadowWalkEl {
|
|
129
|
-
readonly shadowRoot: ShadowWalkRoot | null;
|
|
129
|
+
readonly shadowRoot: ShadowWalkRoot | null | undefined;
|
|
130
130
|
}
|
|
131
|
-
export declare function collectAcrossShadowRoots(root: ShadowWalkRoot | null, selector: string): ShadowWalkEl[];
|
|
131
|
+
export declare function collectAcrossShadowRoots(root: ShadowWalkRoot | null | undefined, selector: string): ShadowWalkEl[];
|
|
132
132
|
export declare function pickSubmitButtonIndex(texts: readonly string[]): number | null;
|
|
133
133
|
export interface ProxySettings {
|
|
134
134
|
server: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/bot/browser.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAS5D,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/bot/browser.ts"],"names":[],"mappings":"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"}
|
package/dist/bot/browser.js
CHANGED
|
@@ -31,10 +31,11 @@ import { startXvfb, xvfbAvailable } from "./xvfb.js";
|
|
|
31
31
|
// the CJS modules lazily (the stealth toolchain only ships CJS) and treat
|
|
32
32
|
// stealth as best-effort — a missing dep should never crash the bot.
|
|
33
33
|
const require = createRequire(import.meta.url);
|
|
34
|
-
// Whether the operator asked for the CDP-hardened launcher
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
34
|
+
// Whether the operator asked for the CDP-hardened launcher (patchright,
|
|
35
|
+
// which runs evaluations in an isolated world and removes the automation
|
|
36
|
+
// tells — mainWorldExecution, navigator.webdriver — that Turnstile /
|
|
37
|
+
// reCAPTCHA-v3 score on). Flag-gated so it can be A/B'd against the
|
|
38
|
+
// stealth baseline — see docs/DESIGN-antibot-hardening.md.
|
|
38
39
|
function cdpHardeningRequested() {
|
|
39
40
|
const v = process.env.BOT_CDP_HARDENED;
|
|
40
41
|
return v === "1" || v === "true" || v === "on";
|
|
@@ -43,7 +44,7 @@ let cachedChromium = null;
|
|
|
43
44
|
// The stealth profile the cached launcher actually represents. Set the
|
|
44
45
|
// first time getChromium() resolves a launcher and read back via
|
|
45
46
|
// BrowserController.stealthProfile for the CaptchaEvent A/B tag. A
|
|
46
|
-
//
|
|
47
|
+
// patchright load failure degrades it to "baseline" truthfully rather
|
|
47
48
|
// than over-claiming "cdp_hardened" on a run that never got the patch.
|
|
48
49
|
let activeStealthProfile = "baseline";
|
|
49
50
|
function activeStealthProfileValue() {
|
|
@@ -54,39 +55,31 @@ function getChromium() {
|
|
|
54
55
|
return cachedChromium;
|
|
55
56
|
const hardened = cdpHardeningRequested();
|
|
56
57
|
try {
|
|
57
|
-
const { addExtra } = require("playwright-extra");
|
|
58
|
-
const stealth = require("puppeteer-extra-plugin-stealth");
|
|
59
|
-
let baseLauncher = baseChromium;
|
|
60
58
|
if (hardened) {
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
const rebrowser = require("rebrowser-playwright-core");
|
|
78
|
-
baseLauncher = rebrowser.chromium;
|
|
59
|
+
// patchright — a maintained Playwright fork that runs every
|
|
60
|
+
// evaluation in an ISOLATED world (so the bot's DOM probing is
|
|
61
|
+
// invisible to a page that traps DOM methods → closes the
|
|
62
|
+
// `mainWorldExecution` tell) and handles `navigator.webdriver`
|
|
63
|
+
// natively + correctly. Verified ALL-GREEN against the maintained
|
|
64
|
+
// rebrowser bot-detector (mainWorldExecution, navigatorWebdriver,
|
|
65
|
+
// viewport, runtimeEnableLeak all clean). It drives real Chrome
|
|
66
|
+
// (channel) directly — the earlier rebrowser fork couldn't, which is
|
|
67
|
+
// why the old hardened arm was forced onto bundled chromium and then
|
|
68
|
+
// crashed the OAuth flow. NO playwright-extra/stealth wrap here: the
|
|
69
|
+
// stealth plugin's manual `navigator.webdriver` defineProperty
|
|
70
|
+
// RE-ADDS a detectable property (proven counterproductive) — patchright
|
|
71
|
+
// does it right. See docs/DESIGN-antibot-hardening.md.
|
|
72
|
+
const patchright = require("patchright");
|
|
73
|
+
cachedChromium = patchright.chromium;
|
|
79
74
|
activeStealthProfile = "cdp_hardened";
|
|
75
|
+
return cachedChromium;
|
|
80
76
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// same stealth wrap (Codex review: a bare import swap would NOT
|
|
88
|
-
// repoint the stealth-wrapped launcher — it must go through addExtra).
|
|
89
|
-
const extra = addExtra(baseLauncher);
|
|
77
|
+
// Baseline: playwright-extra + stealth (unchanged). addExtra(baseChromium)
|
|
78
|
+
// is exactly what playwright-extra's default `chromium` export already is.
|
|
79
|
+
const { addExtra } = require("playwright-extra");
|
|
80
|
+
const stealth = require("puppeteer-extra-plugin-stealth");
|
|
81
|
+
activeStealthProfile = "baseline";
|
|
82
|
+
const extra = addExtra(baseChromium);
|
|
90
83
|
extra.use(stealth());
|
|
91
84
|
cachedChromium = extra;
|
|
92
85
|
}
|
|
@@ -259,8 +252,8 @@ export class BrowserController {
|
|
|
259
252
|
return this.proxyServer;
|
|
260
253
|
}
|
|
261
254
|
// The stealth profile the most recent .start() launched under:
|
|
262
|
-
// "cdp_hardened" when the
|
|
263
|
-
// (BOT_CDP_HARDENED set +
|
|
255
|
+
// "cdp_hardened" when the patchright launcher actually loaded
|
|
256
|
+
// (BOT_CDP_HARDENED set + patchright present), else "baseline". Surfaced
|
|
264
257
|
// for the CaptchaEvent A/B tag. Throws before .start() — same reason
|
|
265
258
|
// as channel/proxied.
|
|
266
259
|
get stealthProfile() {
|
|
@@ -367,30 +360,19 @@ export class BrowserController {
|
|
|
367
360
|
// decide on executablePath below.
|
|
368
361
|
const launcher = getChromium();
|
|
369
362
|
const hardened = activeStealthProfileValue() === "cdp_hardened";
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
// the
|
|
376
|
-
|
|
377
|
-
// executablePath are mutually exclusive in Playwright, so we drop the
|
|
378
|
-
// channel here. (This makes the hardened arm use bundled chromium vs
|
|
379
|
-
// the baseline's real Chrome — a known A/B confound, documented in
|
|
380
|
-
// DESIGN-antibot-hardening.md.)
|
|
381
|
-
const hardenedExecutablePath = hardened ? baseChromium.executablePath() : null;
|
|
382
|
-
const effectiveChannel = hardened ? null : channel;
|
|
383
|
-
// Keep telemetry honest: report what actually launched.
|
|
384
|
-
this.launchedChannel = effectiveChannel;
|
|
363
|
+
// Both launchers drive real Chrome via `channel`: baseline through
|
|
364
|
+
// playwright+stealth, hardened through patchright. patchright closes
|
|
365
|
+
// the automation tells at the protocol layer and drives real Chrome
|
|
366
|
+
// directly — so it no longer needs the bundled-chromium pin the old
|
|
367
|
+
// rebrowser fork required (the pin is what crashed the OAuth flow and
|
|
368
|
+
// confounded the A/B). One binary for both arms.
|
|
369
|
+
this.launchedChannel = channel;
|
|
385
370
|
const context = await launchWithProfileGate(this.profileDir, () => launcher.launchPersistentContext(this.profileDir, {
|
|
386
371
|
headless: chromeHeadless,
|
|
387
372
|
...(chromeEnv !== undefined ? { env: chromeEnv } : {}),
|
|
388
373
|
// `channel:` selects a real installed browser over the bundled
|
|
389
|
-
// binary
|
|
390
|
-
...(
|
|
391
|
-
...(hardenedExecutablePath !== null
|
|
392
|
-
? { executablePath: hardenedExecutablePath }
|
|
393
|
-
: {}),
|
|
374
|
+
// binary (omitted when channel detection found nothing).
|
|
375
|
+
...(channel !== null ? { channel } : {}),
|
|
394
376
|
// `proxy:` routes egress through a residential proxy — only for
|
|
395
377
|
// datacenter-class egress (see resolveProxy()).
|
|
396
378
|
...(proxy !== null ? { proxy } : {}),
|
|
@@ -399,8 +381,17 @@ export class BrowserController {
|
|
|
399
381
|
"--no-sandbox",
|
|
400
382
|
"--disable-dev-shm-usage",
|
|
401
383
|
],
|
|
402
|
-
viewport:
|
|
403
|
-
|
|
384
|
+
// `viewport: null` makes the page use the REAL OS window size
|
|
385
|
+
// instead of a hardcoded value. The old fixed 1280×720 is exactly
|
|
386
|
+
// Playwright's device-emulation default and is flagged by anti-bot
|
|
387
|
+
// detectors as "default Playwright viewport"; the real window
|
|
388
|
+
// (sized by the Xvfb display) reads as an ordinary browser.
|
|
389
|
+
viewport: null,
|
|
390
|
+
// No `userAgent` override: a real Chrome (channel) supplies a UA
|
|
391
|
+
// that AGREES with navigator.userAgentData + the binary version.
|
|
392
|
+
// The old hardcoded "Chrome/131" string mismatched the actual
|
|
393
|
+
// binary (148) — a UA-vs-userAgentData inconsistency that is itself
|
|
394
|
+
// a fingerprint tell. Let the browser report its own coherent UA.
|
|
404
395
|
// locale stays en-US deliberately: matching it to the proxy
|
|
405
396
|
// country would render signup pages in that language, and the
|
|
406
397
|
// Claude vision form-planner expects English.
|
|
@@ -424,10 +415,17 @@ export class BrowserController {
|
|
|
424
415
|
...(geo?.geolocation !== undefined ? { geolocation: geo.geolocation } : {}),
|
|
425
416
|
}));
|
|
426
417
|
this.context = context;
|
|
427
|
-
// Patch
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
418
|
+
// Patch navigator.webdriver — BASELINE ONLY. Measured against the
|
|
419
|
+
// rebrowser bot-detector, this manual `defineProperty` is
|
|
420
|
+
// COUNTERPRODUCTIVE under patchright: it re-adds `webdriver` as an own
|
|
421
|
+
// property the detector then flags, whereas patchright removes it
|
|
422
|
+
// correctly at the source. So in hardened mode we leave it to
|
|
423
|
+
// patchright; only the stealth baseline gets the manual patch.
|
|
424
|
+
if (!hardened) {
|
|
425
|
+
await context.addInitScript(() => {
|
|
426
|
+
Object.defineProperty(navigator, "webdriver", { get: () => undefined });
|
|
427
|
+
});
|
|
428
|
+
}
|
|
431
429
|
// rc.33 — spoof WebGL renderer/vendor. Under Xvfb (or any non-GPU
|
|
432
430
|
// host) Chrome falls back to SwiftShader, which reports
|
|
433
431
|
// UNMASKED_VENDOR_WEBGL = "Google Inc. (Google)"
|
|
@@ -1791,12 +1789,23 @@ export class BrowserController {
|
|
|
1791
1789
|
async findCaptchaWidget() {
|
|
1792
1790
|
if (!this.page)
|
|
1793
1791
|
throw new Error("Browser not started");
|
|
1794
|
-
// Phase 1:
|
|
1792
|
+
// Phase 1: widget shape with polling. page.locator (unlike the
|
|
1793
|
+
// querySelector in detectCaptchaVariant) pierces OPEN shadow roots,
|
|
1794
|
+
// so the Cloudflare iframe is reachable even on modern shadow-DOM
|
|
1795
|
+
// Turnstile embeds. The `.cf-turnstile` host div is added as a
|
|
1796
|
+
// fallback for CLOSED-shadow embeds where the iframe isn't reachable
|
|
1797
|
+
// but the (light-DOM) host is — clicking the host box still triggers
|
|
1798
|
+
// the widget. This mirrors detectCaptchaVariant's iframe-OR-host
|
|
1799
|
+
// check so detection and solving agree (A4).
|
|
1795
1800
|
// Cloudflare Turnstile: src contains "challenges.cloudflare.com"
|
|
1796
1801
|
// reCAPTCHA v2: src contains "recaptcha/api2"
|
|
1797
1802
|
const iframeCandidates = [
|
|
1798
1803
|
{ kind: "turnstile", selector: 'iframe[src*="challenges.cloudflare.com"]' },
|
|
1799
1804
|
{ kind: "recaptcha", selector: 'iframe[src*="recaptcha/api2"]' },
|
|
1805
|
+
// Host-div fallbacks (light DOM) — preferred order keeps the iframe
|
|
1806
|
+
// first when present (more precise click target).
|
|
1807
|
+
{ kind: "turnstile", selector: ".cf-turnstile" },
|
|
1808
|
+
{ kind: "turnstile", selector: "#clerk-captcha" },
|
|
1800
1809
|
];
|
|
1801
1810
|
const iframeDeadline = Date.now() + 5000;
|
|
1802
1811
|
while (Date.now() < iframeDeadline) {
|
|
@@ -2892,7 +2901,16 @@ export class BrowserController {
|
|
|
2892
2901
|
// whole inventory with "Cannot read properties of undefined
|
|
2893
2902
|
// (reading 'querySelectorAll')", failing the run before the
|
|
2894
2903
|
// planner ever saw the page. Skip such a node instead.
|
|
2895
|
-
|
|
2904
|
+
//
|
|
2905
|
+
// `== null` (not `=== null`) is load-bearing: `el.shadowRoot` is
|
|
2906
|
+
// typed `ShadowRoot | null`, but a detached/closed custom element
|
|
2907
|
+
// can yield `undefined` at runtime. The recursion below calls
|
|
2908
|
+
// `walk(el.shadowRoot)` whenever it isn't `null`, so an `undefined`
|
|
2909
|
+
// shadowRoot reaches here and `typeof undefined.querySelectorAll`
|
|
2910
|
+
// THROWS before the typeof guard can fire — exactly the #59
|
|
2911
|
+
// redis-cloud crash, which recurred 2026-06-03 even with the
|
|
2912
|
+
// null-only guard in place. The loose check covers both.
|
|
2913
|
+
if (root == null || typeof root.querySelectorAll !== "function")
|
|
2896
2914
|
return;
|
|
2897
2915
|
root.querySelectorAll(SELECTOR).forEach((n) => collected.push(n));
|
|
2898
2916
|
root.querySelectorAll("*").forEach((el) => {
|
|
@@ -3435,7 +3453,11 @@ export function pickClickLocator(locator, count) {
|
|
|
3435
3453
|
export function collectAcrossShadowRoots(root, selector) {
|
|
3436
3454
|
const collected = [];
|
|
3437
3455
|
const walk = (r) => {
|
|
3438
|
-
|
|
3456
|
+
// `== null` (not `=== null`) covers both null and undefined — the
|
|
3457
|
+
// recursion below calls walk() on any non-null shadowRoot, so an
|
|
3458
|
+
// `undefined` one reaches here and `typeof undefined.querySelectorAll`
|
|
3459
|
+
// would throw before the typeof guard fired (#59 redis-cloud).
|
|
3460
|
+
if (r == null || typeof r.querySelectorAll !== "function")
|
|
3439
3461
|
return;
|
|
3440
3462
|
Array.from(r.querySelectorAll(selector)).forEach((n) => collected.push(n));
|
|
3441
3463
|
Array.from(r.querySelectorAll("*")).forEach((el) => {
|