@reconcrap/boss-recommend-mcp 2.1.13 → 2.1.15

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.
@@ -51,7 +51,8 @@ import {
51
51
  makeForbiddenChatResumeNavigationError
52
52
  } from "./page-guard.js";
53
53
 
54
- export const CHAT_UNSAFE_ONLINE_RESUME_LINK_CODE = "CHAT_UNSAFE_ONLINE_RESUME_LINK";
54
+ export const CHAT_UNSAFE_ONLINE_RESUME_LINK_CODE = "CHAT_UNSAFE_ONLINE_RESUME_LINK";
55
+ export const CHAT_ONLINE_RESUME_MODAL_NOT_OPEN_CODE = "CHAT_ONLINE_RESUME_MODAL_NOT_OPEN";
55
56
 
56
57
  const CHAT_CONVERSATION_CONTROL_SCOPE_SELECTORS = Object.freeze([
57
58
  ".conversation-main",
@@ -128,10 +129,15 @@ export function makeUnsafeChatOnlineResumeLinkError(target = {}, buttonHTML = ""
128
129
  return error;
129
130
  }
130
131
 
131
- export function isUnsafeChatOnlineResumeLinkError(error) {
132
- return error?.code === CHAT_UNSAFE_ONLINE_RESUME_LINK_CODE
133
- || /CHAT_UNSAFE_ONLINE_RESUME_LINK/i.test(String(error?.message || error || ""));
134
- }
132
+ export function isUnsafeChatOnlineResumeLinkError(error) {
133
+ return error?.code === CHAT_UNSAFE_ONLINE_RESUME_LINK_CODE
134
+ || /CHAT_UNSAFE_ONLINE_RESUME_LINK/i.test(String(error?.message || error || ""));
135
+ }
136
+
137
+ export function isChatOnlineResumeModalOpenFailureError(error) {
138
+ return error?.code === CHAT_ONLINE_RESUME_MODAL_NOT_OPEN_CODE
139
+ || /Chat online resume modal did not open/i.test(String(error?.message || error || ""));
140
+ }
135
141
 
136
142
  export function createChatProfileNetworkRecorder(client) {
137
143
  const events = [];
@@ -242,9 +248,9 @@ function chatCandidateIdFromAttributes(attributes = {}) {
242
248
  );
243
249
  }
244
250
 
245
- async function hydrateActiveChatCandidate(client, activeCandidate = null) {
246
- if (!activeCandidate?.node_id) return activeCandidate;
247
- let attributes = {};
251
+ async function hydrateActiveChatCandidate(client, activeCandidate = null) {
252
+ if (!activeCandidate?.node_id) return activeCandidate;
253
+ let attributes = {};
248
254
  let outerHTML = "";
249
255
  try {
250
256
  [attributes, outerHTML] = await Promise.all([
@@ -258,12 +264,25 @@ async function hydrateActiveChatCandidate(client, activeCandidate = null) {
258
264
  candidate_id: chatCandidateIdFromAttributes(attributes) || null,
259
265
  label: normalizeDetailText(htmlToText(outerHTML)),
260
266
  outer_html_length: outerHTML.length
261
- };
262
- }
263
-
264
- export async function waitForChatOnlineResumeButton(client, {
265
- timeoutMs = 12000,
266
- intervalMs = 250,
267
+ };
268
+ }
269
+
270
+ export async function readChatActiveCandidateState(client) {
271
+ const rootState = await getChatRoots(client);
272
+ const activeCandidate = await queryFirstAcrossChatRoots(
273
+ client,
274
+ rootState.roots,
275
+ CHAT_ACTIVE_CANDIDATE_SELECTORS
276
+ );
277
+ return {
278
+ roots: rootState.roots,
279
+ active_candidate: await hydrateActiveChatCandidate(client, activeCandidate)
280
+ };
281
+ }
282
+
283
+ export async function waitForChatOnlineResumeButton(client, {
284
+ timeoutMs = 12000,
285
+ intervalMs = 250,
267
286
  expectedCandidateId = ""
268
287
  } = {}) {
269
288
  const started = Date.now();
@@ -982,10 +1001,12 @@ export async function openChatOnlineResume(client, {
982
1001
  }
983
1002
  }
984
1003
 
985
- const error = new Error("Chat online resume modal did not open");
986
- error.attempts = attempts;
987
- throw error;
988
- }
1004
+ const error = new Error("Chat online resume modal did not open");
1005
+ error.code = CHAT_ONLINE_RESUME_MODAL_NOT_OPEN_CODE;
1006
+ error.retryable = true;
1007
+ error.attempts = attempts;
1008
+ throw error;
1009
+ }
989
1010
 
990
1011
  export async function readChatConversationReadyState(client) {
991
1012
  const rootState = await getChatRoots(client);
@@ -1173,20 +1194,21 @@ export async function sendChatMessage(client, expectedText = "", {
1173
1194
  };
1174
1195
  }
1175
1196
 
1176
- export async function clickChatAskResume(client, {
1177
- timeoutMs = 8000,
1178
- settleMs = 700
1179
- } = {}) {
1197
+ export async function clickChatAskResume(client, {
1198
+ timeoutMs = 8000,
1199
+ settleMs = 700,
1200
+ skipWhenAttachmentResumeAvailable = true
1201
+ } = {}) {
1180
1202
  const started = Date.now();
1181
1203
  let lastState = null;
1182
1204
  let lastDisabledAskResume = null;
1183
1205
  while (Date.now() - started <= timeoutMs) {
1184
1206
  const state = await readChatConversationReadyState(client);
1185
1207
  lastState = state;
1186
- if (state.attachment_resume_enabled) {
1187
- return {
1188
- ok: true,
1189
- already_requested: true,
1208
+ if (skipWhenAttachmentResumeAvailable && state.attachment_resume_enabled) {
1209
+ return {
1210
+ ok: true,
1211
+ already_requested: true,
1190
1212
  attachment_resume_available: true,
1191
1213
  control: state.attachment_resume
1192
1214
  };
@@ -1368,23 +1390,32 @@ export async function waitForChatResumeRequestMessage(client, {
1368
1390
  };
1369
1391
  }
1370
1392
 
1371
- export async function requestChatResumeForPassedCandidate(client, {
1372
- greetingText = "Hi同学,能麻烦发下简历吗?",
1373
- maxAttempts = 3,
1374
- askResumeTimeoutMs = 8000,
1375
- dryRun = false
1376
- } = {}) {
1377
- const effectiveGreetingText = normalizeDetailText(greetingText) || "Hi同学,能麻烦发下简历吗?";
1378
- const initialState = await readChatConversationReadyState(client);
1379
- if (initialState.attachment_resume_enabled) {
1380
- return {
1381
- requested: false,
1382
- skipped: true,
1383
- reason: "attachment_resume_already_available",
1384
- initial_state: initialState
1385
- };
1386
- }
1387
- if (dryRun) {
1393
+ export async function requestChatResumeForPassedCandidate(client, {
1394
+ greetingText = "Hi同学,能麻烦发下简历吗?",
1395
+ maxAttempts = 3,
1396
+ askResumeTimeoutMs = 8000,
1397
+ dryRun = false,
1398
+ skipWhenAttachmentResumeAvailable = true
1399
+ } = {}) {
1400
+ const effectiveGreetingText = normalizeDetailText(greetingText) || "Hi同学,能麻烦发下简历吗?";
1401
+ const initialState = await readChatConversationReadyState(client);
1402
+ if (skipWhenAttachmentResumeAvailable && initialState.attachment_resume_enabled) {
1403
+ return {
1404
+ requested: false,
1405
+ skipped: true,
1406
+ reason: "attachment_resume_already_available",
1407
+ initial_state: initialState
1408
+ };
1409
+ }
1410
+ if (initialState.already_requested_resume) {
1411
+ return {
1412
+ requested: false,
1413
+ skipped: true,
1414
+ reason: "resume_request_already_pending",
1415
+ initial_state: initialState
1416
+ };
1417
+ }
1418
+ if (dryRun) {
1388
1419
  return {
1389
1420
  requested: false,
1390
1421
  skipped: false,
@@ -1416,10 +1447,11 @@ export async function requestChatResumeForPassedCandidate(client, {
1416
1447
 
1417
1448
  const attempts = [];
1418
1449
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
1419
- const before = await getChatResumeRequestMessageState(client);
1420
- const askResult = await clickChatAskResume(client, {
1421
- timeoutMs: askResumeTimeoutMs
1422
- });
1450
+ const before = await getChatResumeRequestMessageState(client);
1451
+ const askResult = await clickChatAskResume(client, {
1452
+ timeoutMs: askResumeTimeoutMs,
1453
+ skipWhenAttachmentResumeAvailable
1454
+ });
1423
1455
  let confirmResult = {
1424
1456
  confirmed: false,
1425
1457
  assumed_requested: Boolean(askResult.already_requested),