@reconcrap/boss-recommend-mcp 1.2.5 → 1.2.7
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/README.md +7 -0
- package/package.json +2 -1
- package/src/adapters.js +402 -95
- package/src/index.js +97 -0
- package/src/pipeline.js +34 -2
- package/src/recommend-healing-config.js +131 -0
- package/src/recommend-healing-rules.json +261 -0
- package/src/self-heal.js +2237 -0
- package/src/test-pipeline.js +67 -0
- package/src/test-self-heal.js +224 -0
- package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +259 -153
- package/vendor/boss-recommend-search-cli/src/cli.js +98 -50
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import readline from "node:readline";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
5
6
|
import CDP from "chrome-remote-interface";
|
|
7
|
+
import {
|
|
8
|
+
buildFirstSelectorLookupExpression,
|
|
9
|
+
getRecommendSelectorRule
|
|
10
|
+
} from "../../../src/recommend-healing-config.js";
|
|
6
11
|
|
|
7
12
|
const DEFAULT_PORT = 9222;
|
|
8
13
|
const RECOMMEND_URL_FRAGMENT = "/web/chat/recommend";
|
|
@@ -14,6 +19,56 @@ const DEGREE_OPTIONS = ["不限", "初中及以下", "中专/中技", "高中",
|
|
|
14
19
|
const DEGREE_ORDER = ["初中及以下", "中专/中技", "高中", "大专", "本科", "硕士", "博士"];
|
|
15
20
|
const GENDER_OPTIONS = ["不限", "男", "女"];
|
|
16
21
|
const RECENT_NOT_VIEW_OPTIONS = ["不限", "近14天没有"];
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
require("../../../src/recommend-healing-rules.json");
|
|
24
|
+
const RECOMMEND_IFRAME_SELECTORS = getRecommendSelectorRule(
|
|
25
|
+
["top", "recommend_iframe"],
|
|
26
|
+
['iframe[name="recommendFrame"]', 'iframe[src*="/web/frame/recommend/"]', "iframe"]
|
|
27
|
+
);
|
|
28
|
+
const FILTER_TRIGGER_SELECTORS = getRecommendSelectorRule(
|
|
29
|
+
["frame", "filter_trigger"],
|
|
30
|
+
[".filter-label-wrap", ".recommend-filter.op-filter"]
|
|
31
|
+
);
|
|
32
|
+
const JOB_DROPDOWN_TRIGGER_SELECTORS = getRecommendSelectorRule(
|
|
33
|
+
["frame", "job_dropdown_trigger"],
|
|
34
|
+
[
|
|
35
|
+
".chat-job-select",
|
|
36
|
+
".chat-job-selector",
|
|
37
|
+
".job-selecter",
|
|
38
|
+
".job-selector",
|
|
39
|
+
".job-select-wrap",
|
|
40
|
+
".job-select",
|
|
41
|
+
".job-select-box",
|
|
42
|
+
".job-wrap",
|
|
43
|
+
".chat-job-name",
|
|
44
|
+
".top-chat-search"
|
|
45
|
+
]
|
|
46
|
+
);
|
|
47
|
+
const JOB_LIST_ITEM_SELECTORS = getRecommendSelectorRule(
|
|
48
|
+
["frame", "job_list_items"],
|
|
49
|
+
[
|
|
50
|
+
".ui-dropmenu-list .job-list .job-item",
|
|
51
|
+
".job-selecter-options .job-list .job-item",
|
|
52
|
+
".job-selector-options .job-list .job-item",
|
|
53
|
+
".dropmenu-list .job-list .job-item",
|
|
54
|
+
".job-list .job-item"
|
|
55
|
+
]
|
|
56
|
+
);
|
|
57
|
+
const JOB_SELECTED_LABEL_SELECTORS = getRecommendSelectorRule(
|
|
58
|
+
["frame", "job_selected_label"],
|
|
59
|
+
[".chat-job-name", ".job-selecter .label", ".job-selecter .job-name", ".job-select .label"]
|
|
60
|
+
);
|
|
61
|
+
const RECOMMEND_CARD_SELECTORS = getRecommendSelectorRule(["frame", "recommend_cards"], ["ul.card-list > li.card-item"]);
|
|
62
|
+
const FEATURED_CARD_SELECTORS = getRecommendSelectorRule(["frame", "featured_cards"], ["li.geek-info-card"]);
|
|
63
|
+
const LATEST_CARD_SELECTORS = getRecommendSelectorRule(["frame", "latest_cards"], [".candidate-card-wrap"]);
|
|
64
|
+
const RECOMMEND_TAB_SELECTORS = getRecommendSelectorRule(
|
|
65
|
+
["frame", "tab_items"],
|
|
66
|
+
["li.tab-item[data-status]", 'li[data-status][class*="tab"]']
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
function buildRecommendFrameExpression() {
|
|
70
|
+
return buildFirstSelectorLookupExpression(RECOMMEND_IFRAME_SELECTORS);
|
|
71
|
+
}
|
|
17
72
|
|
|
18
73
|
function normalizeText(value) {
|
|
19
74
|
return String(value || "").replace(/\s+/g, " ").trim();
|
|
@@ -419,9 +474,7 @@ class RecommendSearchCli {
|
|
|
419
474
|
title
|
|
420
475
|
};
|
|
421
476
|
}
|
|
422
|
-
const frame =
|
|
423
|
-
|| document.querySelector('iframe[src*="/web/frame/recommend/"]')
|
|
424
|
-
|| document.querySelector('iframe');
|
|
477
|
+
const frame = ${buildRecommendFrameExpression()};
|
|
425
478
|
if (!frame || !frame.contentDocument) {
|
|
426
479
|
return { ok: false, error: 'NO_RECOMMEND_IFRAME', currentUrl, title };
|
|
427
480
|
}
|
|
@@ -438,14 +491,16 @@ class RecommendSearchCli {
|
|
|
438
491
|
|
|
439
492
|
async getFilterEntryPoint() {
|
|
440
493
|
return this.evaluate(`(() => {
|
|
441
|
-
const frame =
|
|
442
|
-
|| document.querySelector('iframe[src*="/web/frame/recommend/"]')
|
|
443
|
-
|| document.querySelector('iframe');
|
|
494
|
+
const frame = ${buildRecommendFrameExpression()};
|
|
444
495
|
if (!frame || !frame.contentDocument) {
|
|
445
496
|
return { ok: false, error: 'NO_RECOMMEND_IFRAME' };
|
|
446
497
|
}
|
|
447
498
|
const doc = frame.contentDocument;
|
|
448
|
-
const el =
|
|
499
|
+
const el = ${JSON.stringify(FILTER_TRIGGER_SELECTORS)}
|
|
500
|
+
.map((selector) => {
|
|
501
|
+
try { return doc.querySelector(selector); } catch { return null; }
|
|
502
|
+
})
|
|
503
|
+
.find((node) => node) || null;
|
|
449
504
|
if (!el) {
|
|
450
505
|
return { ok: false, error: 'FILTER_TRIGGER_NOT_FOUND' };
|
|
451
506
|
}
|
|
@@ -461,9 +516,7 @@ class RecommendSearchCli {
|
|
|
461
516
|
|
|
462
517
|
async getJobListState() {
|
|
463
518
|
return this.evaluate(`(() => {
|
|
464
|
-
const frame =
|
|
465
|
-
|| document.querySelector('iframe[src*="/web/frame/recommend/"]')
|
|
466
|
-
|| document.querySelector('iframe');
|
|
519
|
+
const frame = ${buildRecommendFrameExpression()};
|
|
467
520
|
if (!frame || !frame.contentDocument) {
|
|
468
521
|
return { ok: false, error: 'NO_RECOMMEND_IFRAME' };
|
|
469
522
|
}
|
|
@@ -491,13 +544,10 @@ class RecommendSearchCli {
|
|
|
491
544
|
return rect.width > 2 && rect.height > 2;
|
|
492
545
|
};
|
|
493
546
|
|
|
494
|
-
const items =
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
'.dropmenu-list .job-list .job-item',
|
|
499
|
-
'.job-list .job-item'
|
|
500
|
-
].join(',')));
|
|
547
|
+
const items = ${JSON.stringify(JOB_LIST_ITEM_SELECTORS)}
|
|
548
|
+
.flatMap((selector) => {
|
|
549
|
+
try { return Array.from(doc.querySelectorAll(selector)); } catch { return []; }
|
|
550
|
+
});
|
|
501
551
|
const jobs = [];
|
|
502
552
|
const seen = new Set();
|
|
503
553
|
for (const item of items) {
|
|
@@ -516,7 +566,11 @@ class RecommendSearchCli {
|
|
|
516
566
|
});
|
|
517
567
|
}
|
|
518
568
|
|
|
519
|
-
const selectedLabelNode =
|
|
569
|
+
const selectedLabelNode = ${JSON.stringify(JOB_SELECTED_LABEL_SELECTORS)}
|
|
570
|
+
.map((selector) => {
|
|
571
|
+
try { return doc.querySelector(selector); } catch { return null; }
|
|
572
|
+
})
|
|
573
|
+
.find((node) => node) || null;
|
|
520
574
|
return {
|
|
521
575
|
ok: true,
|
|
522
576
|
jobs,
|
|
@@ -530,25 +584,12 @@ class RecommendSearchCli {
|
|
|
530
584
|
|
|
531
585
|
async clickJobDropdownTriggerBySelector() {
|
|
532
586
|
return this.evaluate(`(() => {
|
|
533
|
-
const frame =
|
|
534
|
-
|| document.querySelector('iframe[src*="/web/frame/recommend/"]')
|
|
535
|
-
|| document.querySelector('iframe');
|
|
587
|
+
const frame = ${buildRecommendFrameExpression()};
|
|
536
588
|
if (!frame || !frame.contentDocument) {
|
|
537
589
|
return { ok: false, error: 'NO_RECOMMEND_IFRAME' };
|
|
538
590
|
}
|
|
539
591
|
const doc = frame.contentDocument;
|
|
540
|
-
const selectors =
|
|
541
|
-
'.chat-job-select',
|
|
542
|
-
'.chat-job-selector',
|
|
543
|
-
'.job-selecter',
|
|
544
|
-
'.job-selector',
|
|
545
|
-
'.job-select-wrap',
|
|
546
|
-
'.job-select',
|
|
547
|
-
'.job-select-box',
|
|
548
|
-
'.job-wrap',
|
|
549
|
-
'.chat-job-name',
|
|
550
|
-
'.top-chat-search'
|
|
551
|
-
];
|
|
592
|
+
const selectors = ${JSON.stringify(JOB_DROPDOWN_TRIGGER_SELECTORS)};
|
|
552
593
|
const isVisible = (el) => {
|
|
553
594
|
if (!el) return false;
|
|
554
595
|
const style = getComputedStyle(el);
|
|
@@ -615,9 +656,7 @@ class RecommendSearchCli {
|
|
|
615
656
|
|
|
616
657
|
async clickJobBySelector(job) {
|
|
617
658
|
return this.evaluate(`((job) => {
|
|
618
|
-
const frame =
|
|
619
|
-
|| document.querySelector('iframe[src*="/web/frame/recommend/"]')
|
|
620
|
-
|| document.querySelector('iframe');
|
|
659
|
+
const frame = ${buildRecommendFrameExpression()};
|
|
621
660
|
if (!frame || !frame.contentDocument) {
|
|
622
661
|
return { ok: false, error: 'NO_RECOMMEND_IFRAME' };
|
|
623
662
|
}
|
|
@@ -635,13 +674,10 @@ class RecommendSearchCli {
|
|
|
635
674
|
.trim();
|
|
636
675
|
return strippedSingle || byGap;
|
|
637
676
|
};
|
|
638
|
-
const items =
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
'.dropmenu-list .job-list .job-item',
|
|
643
|
-
'.job-list .job-item'
|
|
644
|
-
].join(',')));
|
|
677
|
+
const items = ${JSON.stringify(JOB_LIST_ITEM_SELECTORS)}
|
|
678
|
+
.flatMap((selector) => {
|
|
679
|
+
try { return Array.from(doc.querySelectorAll(selector)); } catch { return []; }
|
|
680
|
+
});
|
|
645
681
|
const target = items.find((item) => {
|
|
646
682
|
const value = normalize(item.getAttribute('value') || item.dataset?.value || '');
|
|
647
683
|
const label = normalize(item.querySelector('.label')?.textContent || item.textContent || '');
|
|
@@ -1439,20 +1475,30 @@ class RecommendSearchCli {
|
|
|
1439
1475
|
|
|
1440
1476
|
async countCandidates() {
|
|
1441
1477
|
return this.evaluate(`(() => {
|
|
1442
|
-
const frame =
|
|
1443
|
-
|| document.querySelector('iframe[src*="/web/frame/recommend/"]')
|
|
1444
|
-
|| document.querySelector('iframe');
|
|
1478
|
+
const frame = ${buildRecommendFrameExpression()};
|
|
1445
1479
|
if (!frame || !frame.contentDocument) {
|
|
1446
1480
|
return { ok: false, error: 'NO_RECOMMEND_IFRAME' };
|
|
1447
1481
|
}
|
|
1448
1482
|
const doc = frame.contentDocument;
|
|
1449
|
-
const cards =
|
|
1483
|
+
const cards = ${JSON.stringify(RECOMMEND_CARD_SELECTORS)}
|
|
1484
|
+
.flatMap((selector) => {
|
|
1485
|
+
try { return Array.from(doc.querySelectorAll(selector)); } catch { return []; }
|
|
1486
|
+
});
|
|
1450
1487
|
const recommendCandidates = cards.filter((card) => card.querySelector('.card-inner[data-geekid]'));
|
|
1451
|
-
const featuredCards =
|
|
1488
|
+
const featuredCards = ${JSON.stringify(FEATURED_CARD_SELECTORS)}
|
|
1489
|
+
.flatMap((selector) => {
|
|
1490
|
+
try { return Array.from(doc.querySelectorAll(selector)); } catch { return []; }
|
|
1491
|
+
});
|
|
1452
1492
|
const featuredCandidates = featuredCards.filter((card) => card.querySelector('a[data-geekid]'));
|
|
1453
|
-
const latestCards =
|
|
1493
|
+
const latestCards = ${JSON.stringify(LATEST_CARD_SELECTORS)}
|
|
1494
|
+
.flatMap((selector) => {
|
|
1495
|
+
try { return Array.from(doc.querySelectorAll(selector)); } catch { return []; }
|
|
1496
|
+
});
|
|
1454
1497
|
const latestCandidates = latestCards.filter((card) => card.querySelector('.card-inner[data-geek], [data-geek]'));
|
|
1455
|
-
const tabs =
|
|
1498
|
+
const tabs = ${JSON.stringify(RECOMMEND_TAB_SELECTORS)}
|
|
1499
|
+
.flatMap((selector) => {
|
|
1500
|
+
try { return Array.from(doc.querySelectorAll(selector)); } catch { return []; }
|
|
1501
|
+
});
|
|
1456
1502
|
const activeTab = tabs.find((node) => {
|
|
1457
1503
|
const className = String(node.className || '');
|
|
1458
1504
|
const selected = String(node.getAttribute('aria-selected') || '').toLowerCase() === 'true';
|
|
@@ -1648,3 +1694,5 @@ export {
|
|
|
1648
1694
|
normalizeJobTitle,
|
|
1649
1695
|
parseArgs
|
|
1650
1696
|
};
|
|
1697
|
+
|
|
1698
|
+
|