@reconcrap/boss-recommend-mcp 2.0.53 → 2.0.55
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/bin/boss-recommend-mcp.js +0 -0
- package/config/screening-config.example.json +1 -1
- package/package.json +120 -120
- package/src/cli.js +3121 -3121
- package/src/core/run/index.js +310 -310
- package/src/domains/chat/constants.js +229 -220
- package/src/domains/chat/detail.js +1686 -1653
- package/src/domains/chat/run-service.js +2039 -1979
- package/src/domains/common/account-rights-panel.js +314 -0
- package/src/domains/recommend/detail.js +546 -531
- package/src/domains/recommend/run-service.js +1245 -1180
- package/src/domains/recruit/detail.js +15 -0
- package/src/domains/recruit/run-service.js +78 -1
- package/src/recommend-mcp.js +1701 -1701
- package/src/run-state.js +358 -358
|
@@ -13,6 +13,10 @@ import {
|
|
|
13
13
|
buildScreeningCandidateFromDetail,
|
|
14
14
|
htmlToText
|
|
15
15
|
} from "../../core/screening/index.js";
|
|
16
|
+
import {
|
|
17
|
+
closeBossAccountRightsBlockingPanel,
|
|
18
|
+
findBossAccountRightsBlockingPanel
|
|
19
|
+
} from "../common/account-rights-panel.js";
|
|
16
20
|
import {
|
|
17
21
|
RECRUIT_DETAIL_CLOSE_SELECTORS,
|
|
18
22
|
RECRUIT_DETAIL_NETWORK_PATTERNS,
|
|
@@ -64,6 +68,17 @@ export function createRecruitDetailNetworkRecorder(client) {
|
|
|
64
68
|
};
|
|
65
69
|
}
|
|
66
70
|
|
|
71
|
+
export async function findRecruitBlockingPanel(client, options = {}) {
|
|
72
|
+
return findBossAccountRightsBlockingPanel(client, options);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function closeRecruitBlockingPanels(client, options = {}) {
|
|
76
|
+
return closeBossAccountRightsBlockingPanel(client, {
|
|
77
|
+
resolveRoots: getRecruitRoots,
|
|
78
|
+
...options
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
67
82
|
export async function waitForRecruitDetailNetworkEvents(recorder, {
|
|
68
83
|
minCount = 1,
|
|
69
84
|
requireLoaded = true,
|
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
screenCandidate
|
|
45
45
|
} from "../../core/screening/index.js";
|
|
46
46
|
import {
|
|
47
|
+
closeRecruitBlockingPanels,
|
|
47
48
|
closeRecruitDetail,
|
|
48
49
|
createRecruitDetailNetworkRecorder,
|
|
49
50
|
extractRecruitDetailCandidate,
|
|
@@ -159,6 +160,12 @@ function compactError(error, fallbackCode = "RECRUIT_RUN_ERROR") {
|
|
|
159
160
|
code: error.code || fallbackCode,
|
|
160
161
|
message: error.message || String(error)
|
|
161
162
|
};
|
|
163
|
+
if (error.close_result) {
|
|
164
|
+
result.close_result = compactCloseResult(error.close_result);
|
|
165
|
+
}
|
|
166
|
+
if (error.phase) {
|
|
167
|
+
result.phase = error.phase;
|
|
168
|
+
}
|
|
162
169
|
if (error.refresh_attempt) {
|
|
163
170
|
result.refresh_attempt = error.refresh_attempt;
|
|
164
171
|
}
|
|
@@ -174,6 +181,21 @@ function compactError(error, fallbackCode = "RECRUIT_RUN_ERROR") {
|
|
|
174
181
|
return result;
|
|
175
182
|
}
|
|
176
183
|
|
|
184
|
+
function compactCloseResult(closeResult) {
|
|
185
|
+
if (!closeResult) return null;
|
|
186
|
+
const result = {
|
|
187
|
+
closed: Boolean(closeResult.closed),
|
|
188
|
+
reason: closeResult.reason || null,
|
|
189
|
+
probe: closeResult.probe || null,
|
|
190
|
+
attempts: closeResult.attempts || [],
|
|
191
|
+
verification: closeResult.verification || null
|
|
192
|
+
};
|
|
193
|
+
if (closeResult.already_closed !== undefined) {
|
|
194
|
+
result.already_closed = Boolean(closeResult.already_closed);
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
177
199
|
function createRecruitCloseFailureError(closeResult) {
|
|
178
200
|
const error = new Error(closeResult?.reason || "Recruit detail did not close before recovery");
|
|
179
201
|
error.code = "DETAIL_CLOSE_FAILED";
|
|
@@ -181,6 +203,14 @@ function createRecruitCloseFailureError(closeResult) {
|
|
|
181
203
|
return error;
|
|
182
204
|
}
|
|
183
205
|
|
|
206
|
+
function createRecruitBlockingPanelCloseFailureError(closeResult, phase = "") {
|
|
207
|
+
const error = new Error(closeResult?.reason || "Boss account-rights panel did not close before recovery");
|
|
208
|
+
error.code = "ACCOUNT_RIGHTS_PANEL_CLOSE_FAILED";
|
|
209
|
+
error.close_result = closeResult || null;
|
|
210
|
+
error.phase = phase || null;
|
|
211
|
+
return error;
|
|
212
|
+
}
|
|
213
|
+
|
|
184
214
|
function createRecruitRefreshFailureError(refreshAttempt, {
|
|
185
215
|
listEndReason = "",
|
|
186
216
|
targetCount = 0,
|
|
@@ -397,6 +427,7 @@ export async function runRecruitWorkflow({
|
|
|
397
427
|
let refreshRounds = 0;
|
|
398
428
|
let contextRecoveryAttempts = 0;
|
|
399
429
|
const candidateRecoveryCounts = new Map();
|
|
430
|
+
let rootState = null;
|
|
400
431
|
let cardNodeIds = [];
|
|
401
432
|
let listEndReason = "";
|
|
402
433
|
let lastHumanEvent = null;
|
|
@@ -482,6 +513,17 @@ export async function runRecruitWorkflow({
|
|
|
482
513
|
});
|
|
483
514
|
}
|
|
484
515
|
|
|
516
|
+
async function closeRecruitBlockingPanelsForRun(phase = "cleanup") {
|
|
517
|
+
const result = await closeRecruitBlockingPanels(client, {
|
|
518
|
+
attemptsLimit: 2,
|
|
519
|
+
rootState
|
|
520
|
+
});
|
|
521
|
+
if (!result?.closed) {
|
|
522
|
+
throw createRecruitBlockingPanelCloseFailureError(result, phase);
|
|
523
|
+
}
|
|
524
|
+
return result;
|
|
525
|
+
}
|
|
526
|
+
|
|
485
527
|
async function recoverAndReapplyRecruitContext(reason = "context_recovery", error = null, {
|
|
486
528
|
forceRecentViewed = true
|
|
487
529
|
} = {}) {
|
|
@@ -499,11 +541,18 @@ export async function runRecruitWorkflow({
|
|
|
499
541
|
cityOptionTimeoutMs,
|
|
500
542
|
forceRecentViewed
|
|
501
543
|
});
|
|
544
|
+
let blockingPanelClose = null;
|
|
545
|
+
if (refreshResult.ok) {
|
|
546
|
+
blockingPanelClose = await closeRecruitBlockingPanels(client, {
|
|
547
|
+
attemptsLimit: 2
|
|
548
|
+
});
|
|
549
|
+
}
|
|
502
550
|
const compactRefresh = {
|
|
503
551
|
...compactRefreshAttempt(refreshResult),
|
|
504
552
|
context_recovery: true,
|
|
505
553
|
recovery_reason: reason,
|
|
506
554
|
trigger_error: compactError(error, "RECRUIT_CONTEXT_RECOVERY_TRIGGER"),
|
|
555
|
+
account_rights_panel_close: compactCloseResult(blockingPanelClose),
|
|
507
556
|
elapsed_ms: Date.now() - started
|
|
508
557
|
};
|
|
509
558
|
refreshAttempts.push(compactRefresh);
|
|
@@ -525,6 +574,11 @@ export async function runRecruitWorkflow({
|
|
|
525
574
|
});
|
|
526
575
|
throw new Error(`Recruit context recovery failed after ${reason}: ${refreshResult.application?.reason || "refresh returned no cards"}`);
|
|
527
576
|
}
|
|
577
|
+
if (!blockingPanelClose?.closed) {
|
|
578
|
+
const panelError = createRecruitBlockingPanelCloseFailureError(blockingPanelClose, `recover:${reason}`);
|
|
579
|
+
panelError.refresh_attempt = compactRefresh;
|
|
580
|
+
throw panelError;
|
|
581
|
+
}
|
|
528
582
|
rootState = await getRecruitRoots(client);
|
|
529
583
|
rootState = await ensureRecruitViewport(rootState, "recover_after");
|
|
530
584
|
cardNodeIds = await waitForRecruitCardNodeIds(client, rootState.iframe.documentNodeId, {
|
|
@@ -553,11 +607,12 @@ export async function runRecruitWorkflow({
|
|
|
553
607
|
|
|
554
608
|
runControl.setPhase("recruit:cleanup");
|
|
555
609
|
await closeRecruitDetail(client, { attemptsLimit: 2 });
|
|
610
|
+
await closeRecruitBlockingPanelsForRun("cleanup");
|
|
556
611
|
|
|
557
612
|
await runControl.waitIfPaused();
|
|
558
613
|
runControl.throwIfCanceled();
|
|
559
614
|
runControl.setPhase("recruit:roots");
|
|
560
|
-
|
|
615
|
+
rootState = await getRecruitRoots(client);
|
|
561
616
|
rootState = await ensureRecruitViewport(rootState, "roots");
|
|
562
617
|
runControl.checkpoint({
|
|
563
618
|
iframe_selector: rootState.iframe.selector,
|
|
@@ -732,6 +787,25 @@ export async function runRecruitWorkflow({
|
|
|
732
787
|
runControl.setPhase("recruit:detail");
|
|
733
788
|
detailStep = "ensure_viewport";
|
|
734
789
|
rootState = await ensureRecruitViewport(rootState, "detail");
|
|
790
|
+
const blockingPanelClose = await closeRecruitBlockingPanels(client, {
|
|
791
|
+
attemptsLimit: 2,
|
|
792
|
+
rootState
|
|
793
|
+
});
|
|
794
|
+
if (!blockingPanelClose?.closed) {
|
|
795
|
+
const panelError = createRecruitBlockingPanelCloseFailureError(
|
|
796
|
+
blockingPanelClose,
|
|
797
|
+
"before_detail_open"
|
|
798
|
+
);
|
|
799
|
+
timings.account_rights_panel_close = compactCloseResult(blockingPanelClose);
|
|
800
|
+
checkpointInProgressCandidate({ index, candidateKey, cardNodeId, detailStep, error: panelError });
|
|
801
|
+
await recoverAndReapplyRecruitContext("account_rights_panel_before_detail", panelError, {
|
|
802
|
+
forceRecentViewed: true
|
|
803
|
+
});
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (blockingPanelClose.already_closed === false) {
|
|
807
|
+
timings.account_rights_panel_close = compactCloseResult(blockingPanelClose);
|
|
808
|
+
}
|
|
735
809
|
checkpointInProgressCandidate({ index, candidateKey, cardNodeId, detailStep });
|
|
736
810
|
detailStep = "open_detail";
|
|
737
811
|
networkRecorder.clear();
|
|
@@ -835,6 +909,7 @@ export async function runRecruitWorkflow({
|
|
|
835
909
|
timings.image_capture_recovery_trigger = compactError(error, "IMAGE_CAPTURE_FAILED");
|
|
836
910
|
checkpointInProgressCandidate({ index, candidateKey, cardNodeId, detailStep, error });
|
|
837
911
|
await closeRecruitDetail(client, { attemptsLimit: 2 }).catch(() => null);
|
|
912
|
+
await closeRecruitBlockingPanels(client, { attemptsLimit: 2, rootState }).catch(() => null);
|
|
838
913
|
await recoverAndReapplyRecruitContext(`image_capture:${detailStep}`, error, {
|
|
839
914
|
forceRecentViewed: true
|
|
840
915
|
});
|
|
@@ -907,6 +982,7 @@ export async function runRecruitWorkflow({
|
|
|
907
982
|
timings.detail_recovery_trigger = compactRecoverableDetailError(error);
|
|
908
983
|
checkpointInProgressCandidate({ index, candidateKey, cardNodeId, detailStep, error });
|
|
909
984
|
await closeRecruitDetail(client, { attemptsLimit: 2 }).catch(() => null);
|
|
985
|
+
await closeRecruitBlockingPanels(client, { attemptsLimit: 2, rootState }).catch(() => null);
|
|
910
986
|
await recoverAndReapplyRecruitContext(`detail:${detailStep}`, error, {
|
|
911
987
|
forceRecentViewed: true
|
|
912
988
|
});
|
|
@@ -916,6 +992,7 @@ export async function runRecruitWorkflow({
|
|
|
916
992
|
detailResult = null;
|
|
917
993
|
timings.detail_recovered_error = compactRecoverableDetailError(error);
|
|
918
994
|
await closeRecruitDetail(client, { attemptsLimit: 2 }).catch(() => null);
|
|
995
|
+
await closeRecruitBlockingPanels(client, { attemptsLimit: 2, rootState }).catch(() => null);
|
|
919
996
|
}
|
|
920
997
|
}
|
|
921
998
|
|