@reconcrap/boss-recommend-mcp 2.0.23 → 2.0.24
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/domains/chat/detail.js +116 -20
package/package.json
CHANGED
|
@@ -46,6 +46,33 @@ import {
|
|
|
46
46
|
|
|
47
47
|
export const CHAT_UNSAFE_ONLINE_RESUME_LINK_CODE = "CHAT_UNSAFE_ONLINE_RESUME_LINK";
|
|
48
48
|
|
|
49
|
+
const CHAT_CONVERSATION_CONTROL_SCOPE_SELECTORS = Object.freeze([
|
|
50
|
+
".conversation-main",
|
|
51
|
+
".conversation-editor",
|
|
52
|
+
".chat-message-list",
|
|
53
|
+
".toolbar-box-right",
|
|
54
|
+
".operate-exchange-left",
|
|
55
|
+
".operate-icon-item",
|
|
56
|
+
".exchange-tooltip",
|
|
57
|
+
".boss-popup__wrapper",
|
|
58
|
+
".boss-dialog",
|
|
59
|
+
".dialog-wrap.active",
|
|
60
|
+
".geek-detail-modal"
|
|
61
|
+
]);
|
|
62
|
+
|
|
63
|
+
const CHAT_REQUESTED_RESUME_SCOPE_SELECTORS = Object.freeze([
|
|
64
|
+
".chat-message-list",
|
|
65
|
+
".conversation-editor",
|
|
66
|
+
".conversation-main",
|
|
67
|
+
".toolbar-box-right",
|
|
68
|
+
".operate-exchange-left",
|
|
69
|
+
".operate-icon-item",
|
|
70
|
+
".exchange-tooltip",
|
|
71
|
+
".boss-popup__wrapper",
|
|
72
|
+
".boss-dialog",
|
|
73
|
+
".dialog-wrap.active"
|
|
74
|
+
]);
|
|
75
|
+
|
|
49
76
|
export function matchesChatProfileNetwork(url) {
|
|
50
77
|
return CHAT_PROFILE_NETWORK_PATTERNS.some((pattern) => pattern.test(String(url || "")));
|
|
51
78
|
}
|
|
@@ -369,6 +396,20 @@ function countResumeRequestSentMessageMarkers(lines = []) {
|
|
|
369
396
|
), 0);
|
|
370
397
|
}
|
|
371
398
|
|
|
399
|
+
function isResumeAttachmentMessageText(text = "") {
|
|
400
|
+
const normalized = normalizeDetailText(text);
|
|
401
|
+
return Boolean(
|
|
402
|
+
/点击.*附件简历/.test(normalized)
|
|
403
|
+
|| /预览附件简历/.test(normalized)
|
|
404
|
+
|| /查看附件简历/.test(normalized)
|
|
405
|
+
|| /(?:简历|resume)[^\s]*\.(?:pdf|docx?|jpg|jpeg|png)\b/i.test(normalized)
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function countResumeAttachmentMessageMarkers(lines = []) {
|
|
410
|
+
return lines.reduce((total, line) => total + (isResumeAttachmentMessageText(line) ? 1 : 0), 0);
|
|
411
|
+
}
|
|
412
|
+
|
|
372
413
|
function isRequestedResumeControlTarget(target = {}) {
|
|
373
414
|
const label = normalizeDetailText(target.label);
|
|
374
415
|
const className = String(target.attributes?.class || "");
|
|
@@ -402,7 +443,6 @@ function isConfirmText(text = "") {
|
|
|
402
443
|
normalized === "确定"
|
|
403
444
|
|| normalized === "确认"
|
|
404
445
|
|| normalized === "提交"
|
|
405
|
-
|| normalized === "发送"
|
|
406
446
|
|| normalized === "继续"
|
|
407
447
|
|| normalized.includes("确定")
|
|
408
448
|
|| normalized.includes("确认")
|
|
@@ -468,6 +508,35 @@ async function findVisibleMatchingTarget(client, roots, selectors, predicate) {
|
|
|
468
508
|
return null;
|
|
469
509
|
}
|
|
470
510
|
|
|
511
|
+
async function resolveScopedRoots(client, roots = [], selectors = [], {
|
|
512
|
+
fallbackToRoots = true
|
|
513
|
+
} = {}) {
|
|
514
|
+
const scoped = [];
|
|
515
|
+
const seen = new Set();
|
|
516
|
+
for (const root of roots) {
|
|
517
|
+
if (!root?.nodeId) continue;
|
|
518
|
+
for (const selector of selectors) {
|
|
519
|
+
let nodeIds = [];
|
|
520
|
+
try {
|
|
521
|
+
nodeIds = await querySelectorAll(client, root.nodeId, selector);
|
|
522
|
+
} catch {
|
|
523
|
+
nodeIds = [];
|
|
524
|
+
}
|
|
525
|
+
for (const nodeId of nodeIds) {
|
|
526
|
+
const key = `${root.name}:${nodeId}`;
|
|
527
|
+
if (seen.has(key)) continue;
|
|
528
|
+
seen.add(key);
|
|
529
|
+
scoped.push({
|
|
530
|
+
name: `${root.name}:${selector}`,
|
|
531
|
+
nodeId
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (scoped.length || !fallbackToRoots) return scoped;
|
|
537
|
+
return roots;
|
|
538
|
+
}
|
|
539
|
+
|
|
471
540
|
export async function selectChatPrimaryLabel(client, {
|
|
472
541
|
label = "全部",
|
|
473
542
|
timeoutMs = 8000,
|
|
@@ -885,39 +954,53 @@ export async function openChatOnlineResume(client, {
|
|
|
885
954
|
|
|
886
955
|
export async function readChatConversationReadyState(client) {
|
|
887
956
|
const rootState = await getChatRoots(client);
|
|
888
|
-
const
|
|
957
|
+
const scopedControlRoots = await resolveScopedRoots(
|
|
958
|
+
client,
|
|
959
|
+
rootState.roots,
|
|
960
|
+
CHAT_CONVERSATION_CONTROL_SCOPE_SELECTORS,
|
|
961
|
+
{ fallbackToRoots: false }
|
|
962
|
+
);
|
|
963
|
+
const scopedRequestedRoots = await resolveScopedRoots(
|
|
889
964
|
client,
|
|
890
965
|
rootState.roots,
|
|
966
|
+
CHAT_REQUESTED_RESUME_SCOPE_SELECTORS,
|
|
967
|
+
{ fallbackToRoots: false }
|
|
968
|
+
);
|
|
969
|
+
const controlRoots = scopedControlRoots.length ? scopedControlRoots : rootState.roots;
|
|
970
|
+
const requestedRoots = scopedRequestedRoots.length ? scopedRequestedRoots : rootState.roots;
|
|
971
|
+
const onlineResume = await findVisibleMatchingTarget(
|
|
972
|
+
client,
|
|
973
|
+
controlRoots,
|
|
891
974
|
CHAT_ONLINE_RESUME_BUTTON_SELECTORS,
|
|
892
975
|
(target) => target.label.includes("在线简历") && !target.disabled
|
|
893
976
|
);
|
|
894
977
|
const attachmentResume = await findVisibleMatchingTarget(
|
|
895
978
|
client,
|
|
896
|
-
|
|
979
|
+
controlRoots,
|
|
897
980
|
CHAT_ATTACHMENT_RESUME_BUTTON_SELECTORS,
|
|
898
981
|
(target) => isAttachmentResumeText(target.label)
|
|
899
982
|
);
|
|
900
983
|
const askResume = await findVisibleMatchingTarget(
|
|
901
984
|
client,
|
|
902
|
-
|
|
985
|
+
controlRoots,
|
|
903
986
|
CHAT_ASK_RESUME_BUTTON_SELECTORS,
|
|
904
987
|
(target) => isAskResumeText(target.label) && !isAttachmentResumeTarget(target)
|
|
905
988
|
);
|
|
906
989
|
const requestedResume = await findVisibleMatchingTarget(
|
|
907
990
|
client,
|
|
908
|
-
|
|
991
|
+
requestedRoots,
|
|
909
992
|
CHAT_ASK_RESUME_BUTTON_SELECTORS,
|
|
910
993
|
(target) => isRequestedResumeControlTarget(target)
|
|
911
994
|
);
|
|
912
995
|
const editor = await findVisibleMatchingTarget(
|
|
913
996
|
client,
|
|
914
|
-
|
|
997
|
+
controlRoots,
|
|
915
998
|
CHAT_EDITOR_SELECTORS,
|
|
916
999
|
() => true
|
|
917
1000
|
);
|
|
918
1001
|
const sendButton = await findVisibleMatchingTarget(
|
|
919
1002
|
client,
|
|
920
|
-
|
|
1003
|
+
controlRoots,
|
|
921
1004
|
CHAT_SEND_BUTTON_SELECTORS,
|
|
922
1005
|
(target) => isSendText(target.label) || /submit/i.test(String(target.attributes?.class || ""))
|
|
923
1006
|
);
|
|
@@ -1111,19 +1194,18 @@ export async function clickChatConfirmRequestResume(client, {
|
|
|
1111
1194
|
} = {}) {
|
|
1112
1195
|
const started = Date.now();
|
|
1113
1196
|
let lastTarget = null;
|
|
1197
|
+
let lastState = null;
|
|
1114
1198
|
while (Date.now() - started <= timeoutMs) {
|
|
1115
|
-
|
|
1116
|
-
if (state.already_requested_resume) {
|
|
1117
|
-
return {
|
|
1118
|
-
confirmed: true,
|
|
1119
|
-
assumed_requested: true,
|
|
1120
|
-
state
|
|
1121
|
-
};
|
|
1122
|
-
}
|
|
1199
|
+
lastState = await readChatConversationReadyState(client);
|
|
1123
1200
|
const rootState = await getChatRoots(client);
|
|
1124
|
-
const
|
|
1201
|
+
const confirmRoots = await resolveScopedRoots(
|
|
1125
1202
|
client,
|
|
1126
1203
|
rootState.roots,
|
|
1204
|
+
CHAT_CONVERSATION_CONTROL_SCOPE_SELECTORS
|
|
1205
|
+
);
|
|
1206
|
+
const target = await findVisibleMatchingTarget(
|
|
1207
|
+
client,
|
|
1208
|
+
confirmRoots,
|
|
1127
1209
|
CHAT_CONFIRM_REQUEST_RESUME_SELECTORS,
|
|
1128
1210
|
(item) => isConfirmText(item.label) && !item.disabled
|
|
1129
1211
|
);
|
|
@@ -1157,7 +1239,8 @@ export async function clickChatConfirmRequestResume(client, {
|
|
|
1157
1239
|
return {
|
|
1158
1240
|
confirmed: false,
|
|
1159
1241
|
error: "CONFIRM_BUTTON_NOT_FOUND",
|
|
1160
|
-
control: lastTarget
|
|
1242
|
+
control: lastTarget,
|
|
1243
|
+
state: lastState
|
|
1161
1244
|
};
|
|
1162
1245
|
}
|
|
1163
1246
|
|
|
@@ -1185,18 +1268,25 @@ export async function getChatResumeRequestMessageState(client) {
|
|
|
1185
1268
|
} catch {}
|
|
1186
1269
|
const lines = text.split(/\r?\n/).map(normalizeDetailText).filter(Boolean);
|
|
1187
1270
|
const matching = lines.filter((line) => isResumeRequestSentMessageText(line));
|
|
1271
|
+
const attachmentMatching = lines.filter((line) => isResumeAttachmentMessageText(line));
|
|
1188
1272
|
const count = countResumeRequestSentMessageMarkers(lines);
|
|
1273
|
+
const resumeAttachmentCount = countResumeAttachmentMessageMarkers(lines);
|
|
1189
1274
|
return {
|
|
1190
1275
|
ok: Boolean(text),
|
|
1191
1276
|
selector: messageRoot?.selector || "top",
|
|
1192
1277
|
count,
|
|
1278
|
+
resume_attachment_count: resumeAttachmentCount,
|
|
1279
|
+
success_count: count + resumeAttachmentCount,
|
|
1193
1280
|
last_text: matching[matching.length - 1] || lines[lines.length - 1] || "",
|
|
1281
|
+
last_resume_attachment_text: attachmentMatching[attachmentMatching.length - 1] || "",
|
|
1282
|
+
last_success_text: matching[matching.length - 1] || attachmentMatching[attachmentMatching.length - 1] || "",
|
|
1194
1283
|
recent: lines.slice(-12)
|
|
1195
1284
|
};
|
|
1196
1285
|
}
|
|
1197
1286
|
|
|
1198
1287
|
export async function waitForChatResumeRequestMessage(client, {
|
|
1199
1288
|
baselineCount = 0,
|
|
1289
|
+
baselineResumeAttachmentCount = 0,
|
|
1200
1290
|
timeoutMs = 6500,
|
|
1201
1291
|
intervalMs = 260
|
|
1202
1292
|
} = {}) {
|
|
@@ -1204,7 +1294,10 @@ export async function waitForChatResumeRequestMessage(client, {
|
|
|
1204
1294
|
let state = null;
|
|
1205
1295
|
while (Date.now() - started <= timeoutMs) {
|
|
1206
1296
|
state = await getChatResumeRequestMessageState(client);
|
|
1207
|
-
const observed =
|
|
1297
|
+
const observed = (
|
|
1298
|
+
state.count > baselineCount
|
|
1299
|
+
|| state.resume_attachment_count > baselineResumeAttachmentCount
|
|
1300
|
+
);
|
|
1208
1301
|
if (observed) {
|
|
1209
1302
|
return {
|
|
1210
1303
|
observed: true,
|
|
@@ -1305,7 +1398,8 @@ export async function requestChatResumeForPassedCandidate(client, {
|
|
|
1305
1398
|
confirmResult = await clickChatConfirmRequestResume(client);
|
|
1306
1399
|
}
|
|
1307
1400
|
const messageCheck = await waitForChatResumeRequestMessage(client, {
|
|
1308
|
-
baselineCount: before.count
|
|
1401
|
+
baselineCount: before.count,
|
|
1402
|
+
baselineResumeAttachmentCount: before.resume_attachment_count
|
|
1309
1403
|
});
|
|
1310
1404
|
const messageObserved = Boolean(messageCheck.observed);
|
|
1311
1405
|
attempts.push({
|
|
@@ -1314,8 +1408,10 @@ export async function requestChatResumeForPassedCandidate(client, {
|
|
|
1314
1408
|
confirm_result: confirmResult,
|
|
1315
1409
|
message_before_count: before.count,
|
|
1316
1410
|
message_after_count: messageCheck.state?.count || 0,
|
|
1411
|
+
resume_attachment_before_count: before.resume_attachment_count || 0,
|
|
1412
|
+
resume_attachment_after_count: messageCheck.state?.resume_attachment_count || 0,
|
|
1317
1413
|
message_observed: messageObserved,
|
|
1318
|
-
message_last_text: messageCheck.state?.last_text || ""
|
|
1414
|
+
message_last_text: messageCheck.state?.last_success_text || messageCheck.state?.last_text || ""
|
|
1319
1415
|
});
|
|
1320
1416
|
if (messageObserved) {
|
|
1321
1417
|
return {
|