@reconcrap/boss-recommend-mcp 2.0.18 → 2.0.20
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
CHANGED
|
@@ -150,6 +150,14 @@ export const CHAT_RESUME_MODAL_SELECTORS = Object.freeze([
|
|
|
150
150
|
".resume-recommend"
|
|
151
151
|
]);
|
|
152
152
|
|
|
153
|
+
export const CHAT_RESUME_FAST_MODAL_SELECTORS = Object.freeze([
|
|
154
|
+
".boss-popup__wrapper.new-chat-resume-dialog-main-ui",
|
|
155
|
+
".new-chat-resume-dialog-main-ui",
|
|
156
|
+
".resume-common-dialog.search-resume",
|
|
157
|
+
".resume-recommend",
|
|
158
|
+
'iframe[src*="/web/frame/c-resume/"]'
|
|
159
|
+
]);
|
|
160
|
+
|
|
153
161
|
export const CHAT_RESUME_CONTENT_SELECTORS = Object.freeze([
|
|
154
162
|
".resume-center-side .resume-detail-wrap",
|
|
155
163
|
".resume-detail-wrap",
|
|
@@ -171,14 +179,18 @@ export const CHAT_RESUME_IFRAME_SELECTORS = Object.freeze([
|
|
|
171
179
|
export const CHAT_RESUME_CLOSE_SELECTORS = Object.freeze([
|
|
172
180
|
".boss-popup__close",
|
|
173
181
|
".boss-dialog__close",
|
|
182
|
+
".new-chat-resume-dialog-main-ui .boss-popup__close",
|
|
183
|
+
".new-chat-resume-dialog-main-ui .icon-close",
|
|
184
|
+
".new-chat-resume-dialog-main-ui [class*=\"close\"]",
|
|
185
|
+
".boss-popup__wrapper [class*=\"close\"]",
|
|
186
|
+
".boss-dialog [class*=\"close\"]",
|
|
174
187
|
".popup-close",
|
|
175
188
|
".modal-close",
|
|
176
189
|
".dialog-close",
|
|
177
190
|
".close-btn",
|
|
178
191
|
".icon-close",
|
|
179
192
|
'[aria-label*="关闭"]',
|
|
180
|
-
'[title*="关闭"]'
|
|
181
|
-
'[class*="close"]'
|
|
193
|
+
'[title*="关闭"]'
|
|
182
194
|
]);
|
|
183
195
|
|
|
184
196
|
export const CHAT_PROFILE_NETWORK_PATTERNS = Object.freeze([
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
CHAT_PROFILE_NETWORK_PATTERNS,
|
|
29
29
|
CHAT_RESUME_CLOSE_SELECTORS,
|
|
30
30
|
CHAT_RESUME_CONTENT_SELECTORS,
|
|
31
|
+
CHAT_RESUME_FAST_MODAL_SELECTORS,
|
|
31
32
|
CHAT_RESUME_IFRAME_SELECTORS,
|
|
32
33
|
CHAT_RESUME_MODAL_SELECTORS,
|
|
33
34
|
CHAT_SEND_BUTTON_SELECTORS
|
|
@@ -573,6 +574,43 @@ export async function waitForChatResumeModal(client, {
|
|
|
573
574
|
return lastState;
|
|
574
575
|
}
|
|
575
576
|
|
|
577
|
+
export async function quickChatResumeModalOpenProbe(client, {
|
|
578
|
+
selectors = CHAT_RESUME_FAST_MODAL_SELECTORS
|
|
579
|
+
} = {}) {
|
|
580
|
+
const rootState = await getChatRoots(client);
|
|
581
|
+
for (const root of rootState.roots) {
|
|
582
|
+
if (!root?.nodeId) continue;
|
|
583
|
+
for (const selector of selectors) {
|
|
584
|
+
let nodeIds = [];
|
|
585
|
+
try {
|
|
586
|
+
nodeIds = await querySelectorAll(client, root.nodeId, selector);
|
|
587
|
+
} catch {
|
|
588
|
+
nodeIds = [];
|
|
589
|
+
}
|
|
590
|
+
for (const nodeId of nodeIds.slice(0, 4)) {
|
|
591
|
+
try {
|
|
592
|
+
const box = await getNodeBox(client, nodeId);
|
|
593
|
+
if (box?.rect?.width > 8 && box?.rect?.height > 8) {
|
|
594
|
+
return {
|
|
595
|
+
open: true,
|
|
596
|
+
root: root.name,
|
|
597
|
+
selector,
|
|
598
|
+
node_id: nodeId,
|
|
599
|
+
rect: box.rect,
|
|
600
|
+
center: box.center
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
} catch {
|
|
604
|
+
// Hidden or stale modal probes are ignored.
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return {
|
|
610
|
+
open: false
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
|
|
576
614
|
export async function readChatResumeHtml(client, resumeState) {
|
|
577
615
|
let popupHTML = "";
|
|
578
616
|
let contentHTML = "";
|
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
extractChatProfileCandidate,
|
|
53
53
|
isUnsafeChatOnlineResumeLinkError,
|
|
54
54
|
openChatOnlineResume,
|
|
55
|
+
quickChatResumeModalOpenProbe,
|
|
55
56
|
readChatConversationReadyState,
|
|
56
57
|
requestChatResumeForPassedCandidate,
|
|
57
58
|
selectChatMessageFilter,
|
|
@@ -153,6 +154,41 @@ function resultOpenedDetail(result) {
|
|
|
153
154
|
return Boolean(result?.detail && !result.detail?.cv_acquisition?.skipped);
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
export function chatDetailSkipReasonFromReadyState(state = {}) {
|
|
158
|
+
if (state?.attachment_resume_enabled) return "attachment_resume_already_available";
|
|
159
|
+
return "";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function makeChatResumeModalOpenBeforeCandidateClickError(closeResult = null) {
|
|
163
|
+
const error = new Error("CHAT_RESUME_MODAL_OPEN_BEFORE_CANDIDATE_CLICK");
|
|
164
|
+
error.code = "CHAT_RESUME_MODAL_OPEN_BEFORE_CANDIDATE_CLICK";
|
|
165
|
+
error.close_result = closeResult || null;
|
|
166
|
+
return error;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export async function ensureNoOpenChatResumeModalBeforeCandidateClick(client, {
|
|
170
|
+
closeAttempts = 3
|
|
171
|
+
} = {}) {
|
|
172
|
+
const probe = await quickChatResumeModalOpenProbe(client);
|
|
173
|
+
if (!probe.open) {
|
|
174
|
+
return {
|
|
175
|
+
closed: true,
|
|
176
|
+
already_closed: true,
|
|
177
|
+
probe
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const closeResult = await closeChatResumeModal(client, { attemptsLimit: closeAttempts });
|
|
181
|
+
if (closeResult?.closed) {
|
|
182
|
+
return {
|
|
183
|
+
closed: true,
|
|
184
|
+
already_closed: false,
|
|
185
|
+
probe,
|
|
186
|
+
close_result: closeResult
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
throw makeChatResumeModalOpenBeforeCandidateClickError(closeResult);
|
|
190
|
+
}
|
|
191
|
+
|
|
156
192
|
function llmToScreening(llmResult, candidate) {
|
|
157
193
|
return {
|
|
158
194
|
status: llmResult?.passed ? "pass" : "fail",
|
|
@@ -453,6 +489,7 @@ async function selectFreshChatCandidate(client, {
|
|
|
453
489
|
} = {}) {
|
|
454
490
|
let lastError = null;
|
|
455
491
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
492
|
+
const modalGuard = await ensureNoOpenChatResumeModalBeforeCandidateClick(client);
|
|
456
493
|
const rootState = await getChatRoots(client);
|
|
457
494
|
const freshNodeId = await resolveFreshChatCardNodeId(client, {
|
|
458
495
|
fallbackNodeId: cardNodeId,
|
|
@@ -474,6 +511,7 @@ async function selectFreshChatCandidate(client, {
|
|
|
474
511
|
ready,
|
|
475
512
|
card_node_id: freshNodeId,
|
|
476
513
|
refreshed_node: freshNodeId !== cardNodeId,
|
|
514
|
+
modal_guard: modalGuard,
|
|
477
515
|
attempt: attempt + 1
|
|
478
516
|
};
|
|
479
517
|
} catch (error) {
|
|
@@ -962,20 +1000,37 @@ export async function runChatWorkflow({
|
|
|
962
1000
|
}
|
|
963
1001
|
effectiveCardNodeId = selected.card_node_id || cardNodeId;
|
|
964
1002
|
const selectionNetworkEvents = networkRecorder.events.slice();
|
|
1003
|
+
try {
|
|
1004
|
+
preActionState = await readChatConversationReadyState(client);
|
|
1005
|
+
} catch (error) {
|
|
1006
|
+
preActionState = {
|
|
1007
|
+
error: error?.message || String(error)
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
const preDetailSkipReason = chatDetailSkipReasonFromReadyState(preActionState);
|
|
1011
|
+
if (preDetailSkipReason) {
|
|
1012
|
+
detailUnavailableReason = preDetailSkipReason;
|
|
1013
|
+
detailResult = createSkippedDetailResult(cardCandidate, preDetailSkipReason);
|
|
1014
|
+
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
1015
|
+
detailResult.cv_acquisition.selection_ready_state = selected.ready;
|
|
1016
|
+
}
|
|
965
1017
|
if (!selected.ready?.ok) {
|
|
966
|
-
if (
|
|
1018
|
+
if (detailResult) {
|
|
1019
|
+
// Already classified by the pre-detail conversation state.
|
|
1020
|
+
} else if (selected.ready?.reason === "active_candidate_mismatch") {
|
|
967
1021
|
detailUnavailableReason = "active_candidate_mismatch";
|
|
968
1022
|
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason);
|
|
969
1023
|
detailResult.cv_acquisition.selection_ready_state = selected.ready;
|
|
970
1024
|
} else {
|
|
971
1025
|
detailStep = "read_conversation_ready_state";
|
|
972
|
-
preActionState = await readChatConversationReadyState(client);
|
|
973
1026
|
if (preActionState.attachment_resume_enabled) {
|
|
974
1027
|
detailUnavailableReason = "attachment_resume_already_available";
|
|
975
1028
|
detailResult = createSkippedDetailResult(cardCandidate, "attachment_resume_already_available");
|
|
1029
|
+
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
976
1030
|
} else {
|
|
977
1031
|
detailUnavailableReason = "online_resume_button_unavailable";
|
|
978
1032
|
detailResult = createSkippedDetailResult(cardCandidate, detailUnavailableReason);
|
|
1033
|
+
detailResult.cv_acquisition.pre_detail_state = preActionState;
|
|
979
1034
|
}
|
|
980
1035
|
}
|
|
981
1036
|
}
|
|
@@ -1322,6 +1377,9 @@ export async function runChatWorkflow({
|
|
|
1322
1377
|
if (closeResume) {
|
|
1323
1378
|
detailStep = "close_resume_modal";
|
|
1324
1379
|
closeResult = await measureTiming(timings, "close_detail_ms", () => closeChatResumeModal(client));
|
|
1380
|
+
if (!closeResult?.closed) {
|
|
1381
|
+
throw makeChatResumeModalOpenBeforeCandidateClickError(closeResult);
|
|
1382
|
+
}
|
|
1325
1383
|
}
|
|
1326
1384
|
detailResult.close_result = closeResult;
|
|
1327
1385
|
detailResult.image_evidence = imageEvidence;
|