@reconcrap/boss-recommend-mcp 2.1.24 → 2.1.25
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/package.json +1 -1
- package/src/chat-runtime-config.js +7 -5
- package/src/core/browser/index.js +16 -9
- package/src/core/run/index.js +5 -4
- package/src/core/screening/index.js +291 -26
- package/src/domains/chat/action-journal.js +97 -4
- package/src/domains/recommend/actions.js +740 -36
- package/src/domains/recommend/colleague-contact.js +836 -90
- package/src/domains/recommend/detail.js +4029 -128
- package/src/domains/recommend/filters.js +46 -28
- package/src/domains/recommend/jobs.js +32 -3
- package/src/domains/recommend/location.js +93 -46
- package/src/domains/recommend/refresh.js +354 -69
- package/src/domains/recommend/run-service.js +2499 -484
- package/src/recommend-mcp.js +514 -92
package/src/recommend-mcp.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import process from "node:process";
|
|
4
5
|
import {
|
|
@@ -9,7 +10,8 @@ import {
|
|
|
9
10
|
detectBossLoginState,
|
|
10
11
|
enableDomains,
|
|
11
12
|
FORBIDDEN_CDP_METHODS,
|
|
12
|
-
getMainFrameUrl,
|
|
13
|
+
getMainFrameUrl,
|
|
14
|
+
inspectChromeDebugCommandLine,
|
|
13
15
|
isBossLoginUrl,
|
|
14
16
|
waitForMainFrameUrl,
|
|
15
17
|
sleep
|
|
@@ -33,14 +35,15 @@ import {
|
|
|
33
35
|
runSelfHealCheck
|
|
34
36
|
} from "./core/self-heal/index.js";
|
|
35
37
|
import {
|
|
36
|
-
closeRecommendJobDropdown,
|
|
37
|
-
closeRecommendDetail,
|
|
38
|
-
createRecommendRunService,
|
|
39
|
-
getRecommendRoots,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
closeRecommendJobDropdown,
|
|
39
|
+
closeRecommendDetail,
|
|
40
|
+
createRecommendRunService,
|
|
41
|
+
getRecommendRoots,
|
|
42
|
+
inspectRecommendFilteredEmptyState,
|
|
43
|
+
listRecommendJobOptions,
|
|
44
|
+
RECOMMEND_TARGET_URL,
|
|
45
|
+
runRecommendWorkflow
|
|
46
|
+
} from "./domains/recommend/index.js";
|
|
44
47
|
import {
|
|
45
48
|
parseRecommendInstruction
|
|
46
49
|
} from "./parser.js";
|
|
@@ -77,7 +80,7 @@ let recommendRunService = createRecommendRunService({
|
|
|
77
80
|
});
|
|
78
81
|
const recommendRunMeta = new Map();
|
|
79
82
|
|
|
80
|
-
function normalizeText(value) {
|
|
83
|
+
function normalizeText(value) {
|
|
81
84
|
return String(value || "").replace(/\s+/g, " ").trim();
|
|
82
85
|
}
|
|
83
86
|
|
|
@@ -354,6 +357,168 @@ function compactMethodLogForStatus(methodLog = []) {
|
|
|
354
357
|
.filter((entry) => Boolean(entry.method))
|
|
355
358
|
.slice(-STATUS_METHOD_LOG_TAIL_LIMIT);
|
|
356
359
|
}
|
|
360
|
+
|
|
361
|
+
function canonicalRecommendChromeHost(host = "") {
|
|
362
|
+
const normalized = String(host || "").trim().toLowerCase();
|
|
363
|
+
return ["", "localhost", "127.0.0.1", "::1"].includes(normalized)
|
|
364
|
+
? "127.0.0.1"
|
|
365
|
+
: normalized;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function readChromeCommandLineValue(args = [], name = "") {
|
|
369
|
+
const prefix = `--${name}=`;
|
|
370
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
371
|
+
const value = String(args[index] || "");
|
|
372
|
+
if (value.startsWith(prefix)) return value.slice(prefix.length).trim();
|
|
373
|
+
if (value === `--${name}`) return String(args[index + 1] || "").trim();
|
|
374
|
+
}
|
|
375
|
+
return "";
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function resolveExactChromeProfileDirectory(userDataDir, explicitProfileDirectory = "") {
|
|
379
|
+
const resolvedUserDataDir = fs.realpathSync(path.resolve(userDataDir));
|
|
380
|
+
let profileDirectory = String(explicitProfileDirectory || "").trim();
|
|
381
|
+
if (!profileDirectory) {
|
|
382
|
+
const localStatePath = path.join(resolvedUserDataDir, "Local State");
|
|
383
|
+
const localState = JSON.parse(fs.readFileSync(localStatePath, "utf8"));
|
|
384
|
+
const lastActive = Array.isArray(localState?.profile?.last_active_profiles)
|
|
385
|
+
? localState.profile.last_active_profiles.map((item) => String(item || "").trim()).filter(Boolean)
|
|
386
|
+
: [];
|
|
387
|
+
const cachedProfiles = Object.keys(localState?.profile?.info_cache || {}).filter(Boolean);
|
|
388
|
+
const candidates = Array.from(new Set([...lastActive, ...cachedProfiles]));
|
|
389
|
+
if (candidates.length !== 1) {
|
|
390
|
+
const error = new Error(
|
|
391
|
+
"Chrome profile directory is not explicit and Local State does not prove exactly one active profile"
|
|
392
|
+
);
|
|
393
|
+
error.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
394
|
+
throw error;
|
|
395
|
+
}
|
|
396
|
+
profileDirectory = candidates[0];
|
|
397
|
+
}
|
|
398
|
+
const resolvedProfileDir = fs.realpathSync(path.resolve(resolvedUserDataDir, profileDirectory));
|
|
399
|
+
const relativeProfile = path.relative(resolvedUserDataDir, resolvedProfileDir);
|
|
400
|
+
if (!relativeProfile || relativeProfile.startsWith("..") || path.isAbsolute(relativeProfile)) {
|
|
401
|
+
const error = new Error("Chrome profile directory is not a child of the exact user-data directory");
|
|
402
|
+
error.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
403
|
+
throw error;
|
|
404
|
+
}
|
|
405
|
+
return {
|
|
406
|
+
user_data_dir: process.platform === "win32" ? resolvedUserDataDir.toLowerCase() : resolvedUserDataDir,
|
|
407
|
+
profile_directory: relativeProfile.replaceAll("\\", "/")
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
export async function resolveRecommendActionJournalScope({
|
|
412
|
+
host = DEFAULT_RECOMMEND_HOST,
|
|
413
|
+
port = DEFAULT_RECOMMEND_PORT,
|
|
414
|
+
session = null,
|
|
415
|
+
inspectCommandLine = inspectChromeDebugCommandLine,
|
|
416
|
+
strictFresh = false
|
|
417
|
+
} = {}) {
|
|
418
|
+
const canonicalHost = canonicalRecommendChromeHost(host);
|
|
419
|
+
if (canonicalHost !== "127.0.0.1") {
|
|
420
|
+
const error = new Error("Live recommend greetings require a local canonical Chrome profile identity");
|
|
421
|
+
error.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
422
|
+
throw error;
|
|
423
|
+
}
|
|
424
|
+
let userDataDir = "";
|
|
425
|
+
let profileDirectory = "";
|
|
426
|
+
let source = "";
|
|
427
|
+
if (strictFresh === true) {
|
|
428
|
+
let commandLine = null;
|
|
429
|
+
try {
|
|
430
|
+
commandLine = await inspectCommandLine({ host: canonicalHost, port });
|
|
431
|
+
} catch (error) {
|
|
432
|
+
const inspectionError = new Error(
|
|
433
|
+
"RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED: fresh Chrome command-line inspection failed"
|
|
434
|
+
);
|
|
435
|
+
inspectionError.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
436
|
+
inspectionError.retryable = false;
|
|
437
|
+
inspectionError.cause = error;
|
|
438
|
+
throw inspectionError;
|
|
439
|
+
}
|
|
440
|
+
const observedPort = Number(readChromeCommandLineValue(
|
|
441
|
+
commandLine?.arguments,
|
|
442
|
+
"remote-debugging-port"
|
|
443
|
+
));
|
|
444
|
+
if (commandLine?.ok !== true || observedPort !== Number(port)) {
|
|
445
|
+
const inspectionError = new Error(
|
|
446
|
+
"RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED: fresh Chrome process/port identity could not be proven"
|
|
447
|
+
);
|
|
448
|
+
inspectionError.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
449
|
+
inspectionError.retryable = false;
|
|
450
|
+
inspectionError.expected_port = Number(port);
|
|
451
|
+
inspectionError.observed_port = Number.isFinite(observedPort) ? observedPort : null;
|
|
452
|
+
throw inspectionError;
|
|
453
|
+
}
|
|
454
|
+
userDataDir = readChromeCommandLineValue(commandLine.arguments, "user-data-dir");
|
|
455
|
+
profileDirectory = readChromeCommandLineValue(commandLine.arguments, "profile-directory");
|
|
456
|
+
source = `fresh_${commandLine.source || "chrome_command_line"}`;
|
|
457
|
+
} else {
|
|
458
|
+
const injected = session?.profile_identity;
|
|
459
|
+
if (injected?.verified === true) {
|
|
460
|
+
userDataDir = String(injected.user_data_dir || "").trim();
|
|
461
|
+
profileDirectory = String(injected.profile_directory || "").trim();
|
|
462
|
+
source = "session_verified_profile_identity";
|
|
463
|
+
} else {
|
|
464
|
+
let commandLine = null;
|
|
465
|
+
try {
|
|
466
|
+
commandLine = await inspectCommandLine({ host: canonicalHost, port });
|
|
467
|
+
} catch {
|
|
468
|
+
commandLine = null;
|
|
469
|
+
}
|
|
470
|
+
if (commandLine?.ok === true) {
|
|
471
|
+
userDataDir = readChromeCommandLineValue(commandLine.arguments, "user-data-dir");
|
|
472
|
+
profileDirectory = readChromeCommandLineValue(commandLine.arguments, "profile-directory");
|
|
473
|
+
source = commandLine.source || "chrome_command_line";
|
|
474
|
+
}
|
|
475
|
+
if (!userDataDir && session?.chrome?.launched === true) {
|
|
476
|
+
userDataDir = String(session.chrome.user_data_dir || "").trim();
|
|
477
|
+
source = "same_call_chrome_launch";
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (!userDataDir) {
|
|
482
|
+
const error = new Error(
|
|
483
|
+
"RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED: exact Chrome user-data/profile directory could not be proven"
|
|
484
|
+
);
|
|
485
|
+
error.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
486
|
+
error.retryable = false;
|
|
487
|
+
throw error;
|
|
488
|
+
}
|
|
489
|
+
let exactProfile;
|
|
490
|
+
try {
|
|
491
|
+
exactProfile = resolveExactChromeProfileDirectory(userDataDir, profileDirectory);
|
|
492
|
+
} catch (error) {
|
|
493
|
+
const safeError = new Error(
|
|
494
|
+
"RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED: exact Chrome profile directory could not be proven"
|
|
495
|
+
);
|
|
496
|
+
safeError.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
497
|
+
safeError.retryable = false;
|
|
498
|
+
throw safeError;
|
|
499
|
+
}
|
|
500
|
+
if (!exactProfile.user_data_dir || !exactProfile.profile_directory) {
|
|
501
|
+
const error = new Error("Exact Chrome user-data/profile directory could not be proven");
|
|
502
|
+
error.code = "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED";
|
|
503
|
+
throw error;
|
|
504
|
+
}
|
|
505
|
+
const profileHash = crypto.createHash("sha256")
|
|
506
|
+
.update(
|
|
507
|
+
`boss-chrome-profile-v1\u0000${exactProfile.user_data_dir}\u0000${exactProfile.profile_directory}`,
|
|
508
|
+
"utf8"
|
|
509
|
+
)
|
|
510
|
+
.digest("hex");
|
|
511
|
+
return {
|
|
512
|
+
scope: `boss-recommend-profile-v2:${canonicalHost}:profile-sha256:${profileHash}`,
|
|
513
|
+
identity: {
|
|
514
|
+
verified: true,
|
|
515
|
+
source,
|
|
516
|
+
canonical_host: canonicalHost,
|
|
517
|
+
profile_sha256: profileHash,
|
|
518
|
+
profile_directory: exactProfile.profile_directory
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
357
522
|
|
|
358
523
|
function clonePlain(value, fallback = null) {
|
|
359
524
|
try {
|
|
@@ -1728,51 +1893,239 @@ export async function listRecommendJobsTool({ workspaceRoot = "", args = {} } =
|
|
|
1728
1893
|
}
|
|
1729
1894
|
}
|
|
1730
1895
|
|
|
1731
|
-
function compactHealth(check) {
|
|
1732
|
-
if (!check) return null;
|
|
1733
|
-
return {
|
|
1734
|
-
status: check.status,
|
|
1735
|
-
summary: check.summary,
|
|
1736
|
-
drift_report: check.drift_report,
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1896
|
+
function compactHealth(check) {
|
|
1897
|
+
if (!check) return null;
|
|
1898
|
+
return {
|
|
1899
|
+
status: check.status,
|
|
1900
|
+
summary: check.summary,
|
|
1901
|
+
drift_report: check.drift_report,
|
|
1902
|
+
empty_bootstrap_refresh: check.empty_bootstrap_refresh || null,
|
|
1903
|
+
accepted_empty_bootstrap: check.accepted_empty_bootstrap || null,
|
|
1904
|
+
probes: (check.probes || []).map((probe) => ({
|
|
1905
|
+
id: probe.id,
|
|
1906
|
+
type: probe.type,
|
|
1907
|
+
status: probe.status,
|
|
1741
1908
|
count: probe.count,
|
|
1742
1909
|
required: probe.required
|
|
1743
1910
|
}))
|
|
1744
|
-
};
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
const
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1911
|
+
};
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
function hasOnlyCandidateCardsRequiredFailure(check) {
|
|
1915
|
+
const failedRequiredIds = Array.isArray(check?.summary?.failed_required_ids)
|
|
1916
|
+
? check.summary.failed_required_ids
|
|
1917
|
+
: [];
|
|
1918
|
+
const blockedRequiredIds = Array.isArray(check?.summary?.blocked_required_ids)
|
|
1919
|
+
? check.summary.blocked_required_ids
|
|
1920
|
+
: [];
|
|
1921
|
+
return check?.status === HEALTH_STATUS.DEGRADED
|
|
1922
|
+
&& failedRequiredIds.length === 1
|
|
1923
|
+
&& failedRequiredIds[0] === "candidate_cards"
|
|
1924
|
+
&& blockedRequiredIds.length === 0;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
function compactRecommendEmptyStateEvidence(emptyState) {
|
|
1928
|
+
if (!emptyState) return null;
|
|
1929
|
+
return {
|
|
1930
|
+
verified: emptyState.verified === true,
|
|
1931
|
+
reason: emptyState.reason || null,
|
|
1932
|
+
text: emptyState.text || null,
|
|
1933
|
+
node_id: emptyState.node_id ?? null,
|
|
1934
|
+
box: emptyState.box || null,
|
|
1935
|
+
accessibility: emptyState.accessibility ? {
|
|
1936
|
+
available: emptyState.accessibility.available ?? null,
|
|
1937
|
+
verified: emptyState.accessibility.verified === true,
|
|
1938
|
+
reason: emptyState.accessibility.reason || null
|
|
1939
|
+
} : null
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
function hasExactRecommendFilteredEmptyState(emptyState) {
|
|
1944
|
+
return emptyState?.verified === true
|
|
1945
|
+
&& emptyState?.reason === "exact_visible_filtered_empty_state"
|
|
1946
|
+
&& emptyState?.accessibility?.verified === true;
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
function attachRecommendEmptyBootstrapRefreshEvidence(check, refreshEvidence, emptyState = null) {
|
|
1950
|
+
if (!check || refreshEvidence?.attempted !== true) return check;
|
|
1951
|
+
return {
|
|
1952
|
+
...check,
|
|
1953
|
+
empty_bootstrap_refresh: {
|
|
1954
|
+
...refreshEvidence,
|
|
1955
|
+
after: {
|
|
1956
|
+
health: compactHealth(check),
|
|
1957
|
+
empty_state: compactRecommendEmptyStateEvidence(emptyState)
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1963
|
+
export function getRecommendEmptyBootstrapPreflightAction(
|
|
1964
|
+
check,
|
|
1965
|
+
emptyState = null,
|
|
1966
|
+
refreshEvidence = null
|
|
1967
|
+
) {
|
|
1968
|
+
if (check?.status === HEALTH_STATUS.HEALTHY) return "accept_healthy";
|
|
1969
|
+
if (!hasOnlyCandidateCardsRequiredFailure(check)) return "wait";
|
|
1970
|
+
if (!hasExactRecommendFilteredEmptyState(emptyState)) return "wait";
|
|
1971
|
+
if (refreshEvidence?.attempted !== true) return "refresh";
|
|
1972
|
+
if (
|
|
1973
|
+
refreshEvidence.completed !== true
|
|
1974
|
+
|| refreshEvidence.ok !== true
|
|
1975
|
+
|| refreshEvidence.method !== "Page.navigate"
|
|
1976
|
+
|| refreshEvidence.target_url !== RECOMMEND_TARGET_URL
|
|
1977
|
+
) return "wait";
|
|
1978
|
+
return "accept_empty_bootstrap";
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
export function acceptRecommendEmptyBootstrapHealth(check, emptyState, refreshEvidence = null) {
|
|
1982
|
+
if (
|
|
1983
|
+
getRecommendEmptyBootstrapPreflightAction(check, emptyState, refreshEvidence)
|
|
1984
|
+
!== "accept_empty_bootstrap"
|
|
1985
|
+
) return null;
|
|
1986
|
+
|
|
1987
|
+
const healthWithRefresh = attachRecommendEmptyBootstrapRefreshEvidence(
|
|
1988
|
+
check,
|
|
1989
|
+
refreshEvidence,
|
|
1990
|
+
emptyState
|
|
1991
|
+
);
|
|
1992
|
+
return {
|
|
1993
|
+
...healthWithRefresh,
|
|
1994
|
+
accepted_empty_bootstrap: {
|
|
1995
|
+
accepted: true,
|
|
1996
|
+
mode: "exact_filtered_empty_bootstrap",
|
|
1997
|
+
reason: emptyState.reason,
|
|
1998
|
+
original_health_status: check.status,
|
|
1999
|
+
failed_required_ids: [...check.summary.failed_required_ids],
|
|
2000
|
+
blocked_required_ids: [...check.summary.blocked_required_ids],
|
|
2001
|
+
root: "frame",
|
|
2002
|
+
empty_state: compactRecommendEmptyStateEvidence(emptyState),
|
|
2003
|
+
refresh: healthWithRefresh.empty_bootstrap_refresh
|
|
2004
|
+
}
|
|
2005
|
+
};
|
|
2006
|
+
}
|
|
2007
|
+
|
|
2008
|
+
export function isRecommendConnectorHealthAccepted(health) {
|
|
2009
|
+
if (health?.status === HEALTH_STATUS.HEALTHY) return true;
|
|
2010
|
+
const accepted = health?.accepted_empty_bootstrap;
|
|
2011
|
+
return accepted?.accepted === true
|
|
2012
|
+
&& accepted.mode === "exact_filtered_empty_bootstrap"
|
|
2013
|
+
&& accepted.original_health_status === HEALTH_STATUS.DEGRADED
|
|
2014
|
+
&& getRecommendEmptyBootstrapPreflightAction(
|
|
2015
|
+
health,
|
|
2016
|
+
accepted.empty_state,
|
|
2017
|
+
health.empty_bootstrap_refresh
|
|
2018
|
+
) === "accept_empty_bootstrap";
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
async function waitForHealthyRecommend(client, config, {
|
|
2022
|
+
timeoutMs = 90000,
|
|
2023
|
+
intervalMs = 1000,
|
|
2024
|
+
refreshSettleMs = 5000,
|
|
2025
|
+
refreshNavigationTimeoutMs = 20000
|
|
2026
|
+
} = {}) {
|
|
2027
|
+
const started = Date.now();
|
|
2028
|
+
let lastCheck = null;
|
|
2029
|
+
let refreshEvidence = null;
|
|
2030
|
+
while (Date.now() - started <= timeoutMs) {
|
|
2031
|
+
const loginDetection = await detectBossLoginState(client).catch(() => null);
|
|
2032
|
+
if (loginDetection?.requires_login) {
|
|
2033
|
+
return attachRecommendEmptyBootstrapRefreshEvidence({
|
|
2034
|
+
status: "login_required",
|
|
2035
|
+
summary: "Boss login is required",
|
|
2036
|
+
loginDetection
|
|
2037
|
+
}, refreshEvidence);
|
|
2038
|
+
}
|
|
2039
|
+
const roots = await resolveRecommendSelfHealRoots(client, config);
|
|
1763
2040
|
lastCheck = await runSelfHealCheck({
|
|
1764
2041
|
client,
|
|
1765
2042
|
domain: "recommend",
|
|
1766
2043
|
roots: roots.roots,
|
|
1767
2044
|
selectorProbes: config.selectorProbes,
|
|
1768
|
-
accessibilityProbes: config.accessibilityProbes,
|
|
1769
|
-
viewportProbes: config.viewportProbes
|
|
1770
|
-
});
|
|
1771
|
-
if (lastCheck.status === HEALTH_STATUS.HEALTHY)
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
2045
|
+
accessibilityProbes: config.accessibilityProbes,
|
|
2046
|
+
viewportProbes: config.viewportProbes
|
|
2047
|
+
});
|
|
2048
|
+
if (lastCheck.status === HEALTH_STATUS.HEALTHY) {
|
|
2049
|
+
return attachRecommendEmptyBootstrapRefreshEvidence(lastCheck, refreshEvidence);
|
|
2050
|
+
}
|
|
2051
|
+
let emptyState = null;
|
|
2052
|
+
if (hasOnlyCandidateCardsRequiredFailure(lastCheck) && roots.roots.frame) {
|
|
2053
|
+
emptyState = await inspectRecommendFilteredEmptyState(
|
|
2054
|
+
client,
|
|
2055
|
+
roots.roots.frame
|
|
2056
|
+
).catch((error) => ({
|
|
2057
|
+
verified: false,
|
|
2058
|
+
reason: "filtered_empty_state_probe_failed",
|
|
2059
|
+
error: error?.message || String(error)
|
|
2060
|
+
}));
|
|
2061
|
+
}
|
|
2062
|
+
const action = getRecommendEmptyBootstrapPreflightAction(
|
|
2063
|
+
lastCheck,
|
|
2064
|
+
emptyState,
|
|
2065
|
+
refreshEvidence
|
|
2066
|
+
);
|
|
2067
|
+
if (action === "refresh") {
|
|
2068
|
+
const refreshStarted = Date.now();
|
|
2069
|
+
refreshEvidence = {
|
|
2070
|
+
attempted: true,
|
|
2071
|
+
completed: false,
|
|
2072
|
+
ok: false,
|
|
2073
|
+
method: "Page.navigate",
|
|
2074
|
+
target_url: RECOMMEND_TARGET_URL,
|
|
2075
|
+
before: {
|
|
2076
|
+
health: compactHealth(lastCheck),
|
|
2077
|
+
empty_state: compactRecommendEmptyStateEvidence(emptyState)
|
|
2078
|
+
}
|
|
2079
|
+
};
|
|
2080
|
+
try {
|
|
2081
|
+
const navigationResult = await client.Page.navigate({ url: RECOMMEND_TARGET_URL });
|
|
2082
|
+
if (navigationResult?.errorText) {
|
|
2083
|
+
throw new Error(navigationResult.errorText);
|
|
2084
|
+
}
|
|
2085
|
+
const waited = await waitForMainFrameUrl(
|
|
2086
|
+
client,
|
|
2087
|
+
(url) => isBossLoginUrl(url) || !shouldNavigateToRecommend(url),
|
|
2088
|
+
{
|
|
2089
|
+
timeoutMs: refreshNavigationTimeoutMs,
|
|
2090
|
+
intervalMs: Math.max(250, Math.min(1000, intervalMs))
|
|
2091
|
+
}
|
|
2092
|
+
);
|
|
2093
|
+
if (refreshSettleMs > 0) await sleep(refreshSettleMs);
|
|
2094
|
+
refreshEvidence = {
|
|
2095
|
+
...refreshEvidence,
|
|
2096
|
+
completed: true,
|
|
2097
|
+
ok: waited?.ok === true,
|
|
2098
|
+
navigation: {
|
|
2099
|
+
frame_id: navigationResult?.frameId || null,
|
|
2100
|
+
loader_id: navigationResult?.loaderId || null,
|
|
2101
|
+
observed_url: waited?.url || null,
|
|
2102
|
+
observed_url_ok: waited?.ok === true
|
|
2103
|
+
},
|
|
2104
|
+
elapsed_ms: Date.now() - refreshStarted
|
|
2105
|
+
};
|
|
2106
|
+
} catch (error) {
|
|
2107
|
+
refreshEvidence = {
|
|
2108
|
+
...refreshEvidence,
|
|
2109
|
+
completed: true,
|
|
2110
|
+
ok: false,
|
|
2111
|
+
error: error?.message || String(error),
|
|
2112
|
+
elapsed_ms: Date.now() - refreshStarted
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
continue;
|
|
2116
|
+
}
|
|
2117
|
+
if (action === "accept_empty_bootstrap") {
|
|
2118
|
+
const accepted = acceptRecommendEmptyBootstrapHealth(
|
|
2119
|
+
lastCheck,
|
|
2120
|
+
emptyState,
|
|
2121
|
+
refreshEvidence
|
|
2122
|
+
);
|
|
2123
|
+
if (accepted) return accepted;
|
|
2124
|
+
}
|
|
2125
|
+
await sleep(intervalMs);
|
|
2126
|
+
}
|
|
2127
|
+
return attachRecommendEmptyBootstrapRefreshEvidence(lastCheck, refreshEvidence);
|
|
2128
|
+
}
|
|
1776
2129
|
|
|
1777
2130
|
function shouldNavigateToRecommend(url) {
|
|
1778
2131
|
return !String(url || "").includes("/web/chat/recommend");
|
|
@@ -1866,10 +2219,12 @@ async function connectRecommendChromeSession({
|
|
|
1866
2219
|
}
|
|
1867
2220
|
|
|
1868
2221
|
const selfHealConfig = buildRecommendSelfHealConfig();
|
|
1869
|
-
const health = await waitForHealthyRecommend(client, selfHealConfig, {
|
|
1870
|
-
timeoutMs: slowLive ? 180000 : 90000,
|
|
1871
|
-
intervalMs: slowLive ? 1200 : 800
|
|
1872
|
-
|
|
2222
|
+
const health = await waitForHealthyRecommend(client, selfHealConfig, {
|
|
2223
|
+
timeoutMs: slowLive ? 180000 : 90000,
|
|
2224
|
+
intervalMs: slowLive ? 1200 : 800,
|
|
2225
|
+
refreshSettleMs: slowLive ? 12000 : 5000,
|
|
2226
|
+
refreshNavigationTimeoutMs: slowLive ? 45000 : 20000
|
|
2227
|
+
});
|
|
1873
2228
|
if (health?.loginDetection?.requires_login) {
|
|
1874
2229
|
await session.close?.();
|
|
1875
2230
|
throw createBossLoginRequiredError({
|
|
@@ -1880,7 +2235,7 @@ async function connectRecommendChromeSession({
|
|
|
1880
2235
|
chrome: session.chrome || null
|
|
1881
2236
|
});
|
|
1882
2237
|
}
|
|
1883
|
-
if (!health
|
|
2238
|
+
if (!isRecommendConnectorHealthAccepted(health)) {
|
|
1884
2239
|
const latestUrl = await getMainFrameUrl(client).catch(() => currentUrl);
|
|
1885
2240
|
const latestLoginDetection = await detectBossLoginState(client, { currentUrl: latestUrl }).catch(() => ({
|
|
1886
2241
|
requires_login: isBossLoginUrl(latestUrl),
|
|
@@ -2133,38 +2488,42 @@ function buildRecommendFilter(parsed, args = {}) {
|
|
|
2133
2488
|
}];
|
|
2134
2489
|
const recentNotView = withoutUnlimited(parsed.searchParams?.recent_not_view);
|
|
2135
2490
|
if (recentNotView.length) {
|
|
2136
|
-
groups.push({
|
|
2137
|
-
group: "recentNotView",
|
|
2138
|
-
labels: recentNotView,
|
|
2139
|
-
selectAllLabels: true
|
|
2140
|
-
|
|
2491
|
+
groups.push({
|
|
2492
|
+
group: "recentNotView",
|
|
2493
|
+
labels: recentNotView,
|
|
2494
|
+
selectAllLabels: true,
|
|
2495
|
+
verifySticky: true
|
|
2496
|
+
});
|
|
2141
2497
|
}
|
|
2142
2498
|
|
|
2143
2499
|
const degree = withoutUnlimited(parsed.searchParams?.degree);
|
|
2144
2500
|
if (degree.length) {
|
|
2145
|
-
groups.push({
|
|
2146
|
-
group: "degree",
|
|
2147
|
-
labels: degree,
|
|
2148
|
-
selectAllLabels: true
|
|
2149
|
-
|
|
2501
|
+
groups.push({
|
|
2502
|
+
group: "degree",
|
|
2503
|
+
labels: degree,
|
|
2504
|
+
selectAllLabels: true,
|
|
2505
|
+
verifySticky: true
|
|
2506
|
+
});
|
|
2150
2507
|
}
|
|
2151
2508
|
|
|
2152
2509
|
const gender = withoutUnlimited(parsed.searchParams?.gender);
|
|
2153
2510
|
if (gender.length) {
|
|
2154
|
-
groups.push({
|
|
2155
|
-
group: "gender",
|
|
2156
|
-
labels: gender,
|
|
2157
|
-
selectAllLabels: true
|
|
2158
|
-
|
|
2511
|
+
groups.push({
|
|
2512
|
+
group: "gender",
|
|
2513
|
+
labels: gender,
|
|
2514
|
+
selectAllLabels: true,
|
|
2515
|
+
verifySticky: true
|
|
2516
|
+
});
|
|
2159
2517
|
}
|
|
2160
2518
|
|
|
2161
2519
|
const school = withoutUnlimited(parsed.searchParams?.school_tag);
|
|
2162
2520
|
if (school.length) {
|
|
2163
|
-
groups.push({
|
|
2164
|
-
group: "school",
|
|
2165
|
-
labels: school,
|
|
2166
|
-
selectAllLabels: true
|
|
2167
|
-
|
|
2521
|
+
groups.push({
|
|
2522
|
+
group: "school",
|
|
2523
|
+
labels: school,
|
|
2524
|
+
selectAllLabels: true,
|
|
2525
|
+
verifySticky: true
|
|
2526
|
+
});
|
|
2168
2527
|
}
|
|
2169
2528
|
|
|
2170
2529
|
return {
|
|
@@ -2206,7 +2565,14 @@ function normalizeRecommendStartInput(args = {}, parsed, configResolution = null
|
|
|
2206
2565
|
};
|
|
2207
2566
|
}
|
|
2208
2567
|
|
|
2209
|
-
function getRunOptions(
|
|
2568
|
+
function getRunOptions(
|
|
2569
|
+
args,
|
|
2570
|
+
parsed,
|
|
2571
|
+
normalized,
|
|
2572
|
+
session,
|
|
2573
|
+
configResolution = null,
|
|
2574
|
+
actionJournalScope = ""
|
|
2575
|
+
) {
|
|
2210
2576
|
const slowLive = args.slow_live === true;
|
|
2211
2577
|
const executePostAction = args.dry_run_post_action === true
|
|
2212
2578
|
? false
|
|
@@ -2241,8 +2607,16 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
|
|
|
2241
2607
|
maxGreetCount: normalized.maxGreetCount,
|
|
2242
2608
|
executePostAction,
|
|
2243
2609
|
actionTimeoutMs: parsePositiveInteger(args.action_timeout_ms, slowLive ? 12000 : 8000),
|
|
2244
|
-
actionIntervalMs: parsePositiveInteger(args.action_interval_ms, 500),
|
|
2245
|
-
actionAfterClickDelayMs: parseNonNegativeInteger(args.action_after_click_delay_ms, slowLive ? 1200 : 900),
|
|
2610
|
+
actionIntervalMs: parsePositiveInteger(args.action_interval_ms, 500),
|
|
2611
|
+
actionAfterClickDelayMs: parseNonNegativeInteger(args.action_after_click_delay_ms, slowLive ? 1200 : 900),
|
|
2612
|
+
actionJournalScope,
|
|
2613
|
+
reverifyActionJournalScope: actionJournalScope
|
|
2614
|
+
? async () => resolveRecommendActionJournalScope({
|
|
2615
|
+
host: normalized.host,
|
|
2616
|
+
port: normalized.port,
|
|
2617
|
+
strictFresh: true
|
|
2618
|
+
})
|
|
2619
|
+
: null,
|
|
2246
2620
|
screeningMode: normalized.screeningMode,
|
|
2247
2621
|
llmConfig: normalized.screeningMode === "llm" && configResolution?.ok ? {
|
|
2248
2622
|
...configResolution.config
|
|
@@ -2324,14 +2698,27 @@ function prepareRecommendPipelineStart(args = {}, { workspaceRoot = "" } = {}) {
|
|
|
2324
2698
|
};
|
|
2325
2699
|
}
|
|
2326
2700
|
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2701
|
+
export function shouldPreserveRecommendDetailOnTerminal(snapshot = null) {
|
|
2702
|
+
return snapshot?.checkpoint?.preserve_detail_on_terminal === true
|
|
2703
|
+
&& snapshot?.checkpoint?.action_result_critical_persisted !== true;
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
async function closeRecommendRunSession(runId) {
|
|
2707
|
+
const meta = recommendRunMeta.get(runId);
|
|
2708
|
+
if (!meta || meta.closed) return;
|
|
2709
|
+
try {
|
|
2710
|
+
try {
|
|
2711
|
+
let preserveDetail = false;
|
|
2712
|
+
try {
|
|
2713
|
+
const snapshot = recommendRunService.getRecommendRun(runId);
|
|
2714
|
+
preserveDetail = shouldPreserveRecommendDetailOnTerminal(snapshot);
|
|
2715
|
+
} catch {
|
|
2716
|
+
// If the in-memory run is unavailable, retain the existing best-effort cleanup policy.
|
|
2717
|
+
}
|
|
2718
|
+
meta.preserve_detail_on_terminal = preserveDetail;
|
|
2719
|
+
if (meta.session?.client && !preserveDetail) {
|
|
2720
|
+
await closeRecommendDetail(meta.session.client, { attemptsLimit: 2 });
|
|
2721
|
+
}
|
|
2335
2722
|
} catch {
|
|
2336
2723
|
// Cleanup is best-effort once the run has settled.
|
|
2337
2724
|
}
|
|
@@ -2411,12 +2798,46 @@ async function startRecommendPipelineRunInternal(args = {}, { workspaceRoot = ""
|
|
|
2411
2798
|
},
|
|
2412
2799
|
chrome: error?.chrome || null
|
|
2413
2800
|
};
|
|
2414
|
-
}
|
|
2415
|
-
|
|
2416
|
-
let
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2801
|
+
}
|
|
2802
|
+
|
|
2803
|
+
let actionJournalScope = "";
|
|
2804
|
+
let actionProfileIdentity = null;
|
|
2805
|
+
const liveGreetingRequested = normalized.postAction === "greet"
|
|
2806
|
+
&& args.dry_run_post_action !== true
|
|
2807
|
+
&& args.execute_post_action !== false;
|
|
2808
|
+
if (liveGreetingRequested) {
|
|
2809
|
+
try {
|
|
2810
|
+
const resolvedScope = await resolveRecommendActionJournalScope({
|
|
2811
|
+
host: normalized.host,
|
|
2812
|
+
port: normalized.port,
|
|
2813
|
+
session
|
|
2814
|
+
});
|
|
2815
|
+
actionJournalScope = resolvedScope.scope;
|
|
2816
|
+
actionProfileIdentity = resolvedScope.identity;
|
|
2817
|
+
} catch (error) {
|
|
2818
|
+
await session.close?.();
|
|
2819
|
+
return {
|
|
2820
|
+
status: "FAILED",
|
|
2821
|
+
error: {
|
|
2822
|
+
code: error?.code || "RECOMMEND_ACTION_PROFILE_IDENTITY_UNVERIFIED",
|
|
2823
|
+
message: error?.message || "Exact Chrome profile identity could not be proven",
|
|
2824
|
+
retryable: false
|
|
2825
|
+
}
|
|
2826
|
+
};
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
let started;
|
|
2831
|
+
try {
|
|
2832
|
+
started = recommendRunService.startRecommendRun({
|
|
2833
|
+
...getRunOptions(
|
|
2834
|
+
args,
|
|
2835
|
+
parsed,
|
|
2836
|
+
normalized,
|
|
2837
|
+
session,
|
|
2838
|
+
configResolution,
|
|
2839
|
+
actionJournalScope
|
|
2840
|
+
),
|
|
2420
2841
|
runId: fixedRunId || undefined,
|
|
2421
2842
|
pid: process.pid
|
|
2422
2843
|
});
|
|
@@ -2443,8 +2864,9 @@ async function startRecommendPipelineRunInternal(args = {}, { workspaceRoot = ""
|
|
|
2443
2864
|
host: normalized.host,
|
|
2444
2865
|
port: normalized.port,
|
|
2445
2866
|
target_url: session.navigation?.url || session.target?.url || RECOMMEND_TARGET_URL,
|
|
2446
|
-
target_id: session.target?.id || null,
|
|
2447
|
-
auto_launch: session.chrome || null
|
|
2867
|
+
target_id: session.target?.id || null,
|
|
2868
|
+
auto_launch: session.chrome || null,
|
|
2869
|
+
action_profile_identity: actionProfileIdentity
|
|
2448
2870
|
},
|
|
2449
2871
|
health: session.health || null
|
|
2450
2872
|
});
|