@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.
@@ -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
- let rootState = await getRecruitRoots(client);
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