@reconcrap/boss-recommend-mcp 2.0.47 → 2.0.48

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.
Files changed (53) hide show
  1. package/bin/boss-recommend-mcp.js +4 -4
  2. package/config/screening-config.example.json +27 -27
  3. package/package.json +1 -1
  4. package/scripts/postinstall.cjs +44 -44
  5. package/skills/boss-chat/README.md +39 -39
  6. package/skills/boss-chat/SKILL.md +93 -93
  7. package/skills/boss-recommend-pipeline/README.md +12 -12
  8. package/skills/boss-recommend-pipeline/SKILL.md +180 -180
  9. package/skills/boss-recruit-pipeline/README.md +17 -17
  10. package/skills/boss-recruit-pipeline/SKILL.md +58 -58
  11. package/src/chat-mcp.js +1780 -1780
  12. package/src/chat-runtime-config.js +749 -749
  13. package/src/cli.js +3054 -3054
  14. package/src/core/boss-cards/index.js +199 -199
  15. package/src/core/browser/index.js +1586 -1453
  16. package/src/core/capture/index.js +1201 -1201
  17. package/src/core/cv-acquisition/index.js +238 -238
  18. package/src/core/cv-capture-target/index.js +299 -299
  19. package/src/core/greet-quota/index.js +54 -54
  20. package/src/core/infinite-list/index.js +1326 -1326
  21. package/src/core/reporting/legacy-csv.js +341 -341
  22. package/src/core/run/timing.js +33 -33
  23. package/src/core/self-heal/index.js +973 -973
  24. package/src/core/self-heal/viewport.js +564 -564
  25. package/src/domains/chat/cards.js +137 -137
  26. package/src/domains/chat/constants.js +221 -221
  27. package/src/domains/chat/detail.js +1668 -1668
  28. package/src/domains/chat/index.js +7 -7
  29. package/src/domains/chat/jobs.js +592 -592
  30. package/src/domains/chat/page-guard.js +98 -98
  31. package/src/domains/chat/roots.js +56 -56
  32. package/src/domains/chat/run-service.js +1977 -1977
  33. package/src/domains/recommend/actions.js +457 -457
  34. package/src/domains/recommend/cards.js +243 -243
  35. package/src/domains/recommend/constants.js +165 -165
  36. package/src/domains/recommend/filters.js +610 -610
  37. package/src/domains/recommend/index.js +10 -10
  38. package/src/domains/recommend/jobs.js +316 -316
  39. package/src/domains/recommend/refresh.js +472 -472
  40. package/src/domains/recommend/roots.js +80 -80
  41. package/src/domains/recommend/scopes.js +246 -246
  42. package/src/domains/recruit/actions.js +277 -277
  43. package/src/domains/recruit/cards.js +74 -74
  44. package/src/domains/recruit/constants.js +167 -167
  45. package/src/domains/recruit/detail.js +461 -461
  46. package/src/domains/recruit/index.js +9 -9
  47. package/src/domains/recruit/instruction-parser.js +451 -451
  48. package/src/domains/recruit/refresh.js +44 -44
  49. package/src/domains/recruit/roots.js +68 -68
  50. package/src/domains/recruit/run-service.js +1207 -1207
  51. package/src/domains/recruit/search.js +1202 -1202
  52. package/src/recommend-mcp.js +22 -22
  53. package/src/recruit-mcp.js +1338 -1338
@@ -1,74 +1,74 @@
1
- import {
2
- getAttributesMap,
3
- getOuterHTML,
4
- querySelectorAll,
5
- sleep
6
- } from "../../core/browser/index.js";
7
- import { mergeBossCandidateCardFields } from "../../core/boss-cards/index.js";
8
- import { normalizeCandidateFromHtml } from "../../core/screening/index.js";
9
- import { RECRUIT_CARD_SELECTOR } from "./constants.js";
10
-
11
- function mergeRecruitCardFields(candidate, outerHTML = "") {
12
- return mergeBossCandidateCardFields(candidate, outerHTML, {
13
- metadataKey: "search_card_fields"
14
- });
15
- }
16
-
17
- export async function findRecruitCardNodeIds(client, frameNodeId, {
18
- selector = RECRUIT_CARD_SELECTOR
19
- } = {}) {
20
- return querySelectorAll(client, frameNodeId, selector);
21
- }
22
-
23
- export async function waitForRecruitCardNodeIds(client, frameNodeId, {
24
- selector = RECRUIT_CARD_SELECTOR,
25
- timeoutMs = 12000,
26
- intervalMs = 300
27
- } = {}) {
28
- const started = Date.now();
29
- let nodeIds = [];
30
- while (Date.now() - started <= timeoutMs) {
31
- nodeIds = await findRecruitCardNodeIds(client, frameNodeId, { selector });
32
- if (nodeIds.length) return nodeIds;
33
- await sleep(intervalMs);
34
- }
35
- return nodeIds;
36
- }
37
-
38
- export async function readRecruitCardCandidate(client, cardNodeId, {
39
- targetUrl = "",
40
- source = "recruit-domain-card",
41
- metadata = {}
42
- } = {}) {
43
- const [attributes, outerHTML] = await Promise.all([
44
- getAttributesMap(client, cardNodeId),
45
- getOuterHTML(client, cardNodeId)
46
- ]);
47
- const candidate = normalizeCandidateFromHtml({
48
- domain: "recruit",
49
- source,
50
- html: outerHTML,
51
- attributes,
52
- metadata: {
53
- target_url: targetUrl,
54
- card_node_id: cardNodeId,
55
- ...metadata
56
- }
57
- });
58
- return mergeRecruitCardFields(candidate, outerHTML);
59
- }
60
-
61
- export async function readFirstRecruitCardCandidate(client, frameNodeId, options = {}) {
62
- const cardNodeIds = await findRecruitCardNodeIds(client, frameNodeId, options);
63
- if (!cardNodeIds.length) {
64
- throw new Error("No recruit/search candidate cards found");
65
- }
66
-
67
- const candidate = await readRecruitCardCandidate(client, cardNodeIds[0], options);
68
- return {
69
- card_count: cardNodeIds.length,
70
- first_card_node_id: cardNodeIds[0],
71
- card_node_ids: cardNodeIds,
72
- candidate
73
- };
74
- }
1
+ import {
2
+ getAttributesMap,
3
+ getOuterHTML,
4
+ querySelectorAll,
5
+ sleep
6
+ } from "../../core/browser/index.js";
7
+ import { mergeBossCandidateCardFields } from "../../core/boss-cards/index.js";
8
+ import { normalizeCandidateFromHtml } from "../../core/screening/index.js";
9
+ import { RECRUIT_CARD_SELECTOR } from "./constants.js";
10
+
11
+ function mergeRecruitCardFields(candidate, outerHTML = "") {
12
+ return mergeBossCandidateCardFields(candidate, outerHTML, {
13
+ metadataKey: "search_card_fields"
14
+ });
15
+ }
16
+
17
+ export async function findRecruitCardNodeIds(client, frameNodeId, {
18
+ selector = RECRUIT_CARD_SELECTOR
19
+ } = {}) {
20
+ return querySelectorAll(client, frameNodeId, selector);
21
+ }
22
+
23
+ export async function waitForRecruitCardNodeIds(client, frameNodeId, {
24
+ selector = RECRUIT_CARD_SELECTOR,
25
+ timeoutMs = 12000,
26
+ intervalMs = 300
27
+ } = {}) {
28
+ const started = Date.now();
29
+ let nodeIds = [];
30
+ while (Date.now() - started <= timeoutMs) {
31
+ nodeIds = await findRecruitCardNodeIds(client, frameNodeId, { selector });
32
+ if (nodeIds.length) return nodeIds;
33
+ await sleep(intervalMs);
34
+ }
35
+ return nodeIds;
36
+ }
37
+
38
+ export async function readRecruitCardCandidate(client, cardNodeId, {
39
+ targetUrl = "",
40
+ source = "recruit-domain-card",
41
+ metadata = {}
42
+ } = {}) {
43
+ const [attributes, outerHTML] = await Promise.all([
44
+ getAttributesMap(client, cardNodeId),
45
+ getOuterHTML(client, cardNodeId)
46
+ ]);
47
+ const candidate = normalizeCandidateFromHtml({
48
+ domain: "recruit",
49
+ source,
50
+ html: outerHTML,
51
+ attributes,
52
+ metadata: {
53
+ target_url: targetUrl,
54
+ card_node_id: cardNodeId,
55
+ ...metadata
56
+ }
57
+ });
58
+ return mergeRecruitCardFields(candidate, outerHTML);
59
+ }
60
+
61
+ export async function readFirstRecruitCardCandidate(client, frameNodeId, options = {}) {
62
+ const cardNodeIds = await findRecruitCardNodeIds(client, frameNodeId, options);
63
+ if (!cardNodeIds.length) {
64
+ throw new Error("No recruit/search candidate cards found");
65
+ }
66
+
67
+ const candidate = await readRecruitCardCandidate(client, cardNodeIds[0], options);
68
+ return {
69
+ card_count: cardNodeIds.length,
70
+ first_card_node_id: cardNodeIds[0],
71
+ card_node_ids: cardNodeIds,
72
+ candidate
73
+ };
74
+ }
@@ -1,167 +1,167 @@
1
- export const RECRUIT_TARGET_URL = "https://www.zhipin.com/web/chat/search";
2
-
3
- export const RECRUIT_IFRAME_SELECTORS = Object.freeze([
4
- 'iframe[name="searchFrame"]',
5
- 'iframe[src*="/web/frame/search/"]',
6
- "iframe"
7
- ]);
8
-
9
- export const RECRUIT_CARD_SELECTOR = [
10
- "li.geek-info-card a[data-jid]",
11
- "li.geek-info-card a[data-geekid]",
12
- ".geek-info-card a[data-jid]",
13
- ".geek-info-card a[data-geekid]",
14
- ".geek-info-card a",
15
- "a[data-jid]",
16
- "a[data-geekid]"
17
- ].join(", ");
18
-
19
- export const RECRUIT_LIST_CONTAINER_SELECTORS = Object.freeze([
20
- ".search-list",
21
- ".search-result-list",
22
- ".candidate-list",
23
- ".geek-list",
24
- ".geek-list-wrap",
25
- ".card-list",
26
- ".list-wrap",
27
- ".search-content",
28
- ".search-container"
29
- ]);
30
-
31
- export const RECRUIT_NO_DATA_SELECTORS = Object.freeze([
32
- "i.tip-nodata",
33
- ".tip-nodata",
34
- ".empty-tip",
35
- ".empty-text",
36
- '[class*="empty"]'
37
- ]);
38
-
39
- export const RECRUIT_BOTTOM_MARKER_SELECTORS = Object.freeze([
40
- ".finished-wrap",
41
- ".loadmore",
42
- ".load-tips",
43
- ".tip-nodata",
44
- ".empty-tip",
45
- ".empty-text",
46
- ".no-data",
47
- "[class*=\"finished\"]",
48
- "[class*=\"loadmore\"]",
49
- "[class*=\"load-tips\"]",
50
- "[class*=\"empty\"]"
51
- ]);
52
-
53
- export const RECRUIT_BOTTOM_REFRESH_SELECTORS = Object.freeze([
54
- ".finished-wrap .btn-refresh",
55
- ".finished-wrap .btn",
56
- ".no-data-refresh .btn-refresh",
57
- ".no-data-refresh .btn",
58
- "[class*=\"refresh\"]",
59
- "[ka*=\"refresh\"]",
60
- "button",
61
- "a"
62
- ]);
63
-
64
- export const RECRUIT_SEARCH_SELECTORS = Object.freeze({
65
- keywordInput: [
66
- "input.search-input",
67
- ".search-box input",
68
- ".search-wrap input",
69
- 'input[placeholder*="搜索"]',
70
- "input"
71
- ],
72
- searchButton: [
73
- ".icon-search",
74
- ".search-btn",
75
- 'button[ka*="search"]',
76
- '[class*="search"][class*="btn"]'
77
- ],
78
- jobTitleOption: [
79
- '.search-job-list-C li[ka="search_select_job"]',
80
- ".search-job-list-C li",
81
- '[ka="search_select_job"]'
82
- ],
83
- degreeOption: [
84
- ".degree-list-C .degree-item",
85
- ".degree-list-C li",
86
- ".degree-item",
87
- '[ka*="degree"]'
88
- ],
89
- schoolItem: [
90
- ".school-item",
91
- ".school-list-C .school-item",
92
- ".school-list-C li",
93
- '[class*="school"][class*="item"]'
94
- ],
95
- schoolClickable: [
96
- "label.checkbox",
97
- "label",
98
- ".checkbox",
99
- ".checkbox-text"
100
- ],
101
- recentViewedLabel: [
102
- 'label.checkbox.high_search_checkbox[ka="search_change_view_resume"]',
103
- "label.checkbox.high_search_checkbox",
104
- "label.checkbox",
105
- '[ka="search_change_view_resume"]'
106
- ],
107
- cityInput: [
108
- ".city-wrap .search-city-kw input",
109
- ".search-city-kw input",
110
- ".city-wrap input",
111
- 'input[placeholder*="城市"]'
112
- ],
113
- citySearchResult: [
114
- ".city-box .search-result-C .search-result-item",
115
- ".search-result-C .search-result-item",
116
- ".city-box li",
117
- ".dropdown-city li"
118
- ],
119
- cityProvinceItem: [
120
- ".dropdown-province li"
121
- ],
122
- cityDropdownItem: [
123
- ".dropdown-city li"
124
- ]
125
- });
126
-
127
- export const RECRUIT_DETAIL_POPUP_SELECTORS = Object.freeze([
128
- ".dialog-wrap.active",
129
- ".boss-popup__wrapper",
130
- ".boss-popup_wrapper",
131
- ".boss-dialog_wrapper",
132
- ".boss-dialog",
133
- ".resume-item-detail",
134
- ".geek-detail-modal",
135
- ".resume-container",
136
- '[class*="popup"][class*="wrapper"]',
137
- '[class*="dialog"][class*="wrapper"]'
138
- ]);
139
-
140
- export const RECRUIT_DETAIL_RESUME_IFRAME_SELECTORS = Object.freeze([
141
- 'iframe[src*="/web/frame/c-resume/"]',
142
- 'iframe[name*="resume"]'
143
- ]);
144
-
145
- export const RECRUIT_DETAIL_CLOSE_SELECTORS = Object.freeze([
146
- ".boss-popup__close",
147
- ".popup-close",
148
- ".modal-close",
149
- ".dialog-close",
150
- ".close-btn",
151
- 'button[aria-label*="关闭"]',
152
- 'button[title*="关闭"]',
153
- ".icon-close",
154
- '[aria-label*="关闭"]',
155
- '[title*="关闭"]',
156
- '[class*="close"]'
157
- ]);
158
-
159
- export const RECRUIT_DETAIL_NETWORK_PATTERNS = Object.freeze([
160
- /\/wapi\/zpitem\/web\/boss\/search\/geek\/info\b/i,
161
- /\/wapi\/zpjob\/view\/geek\/info(?:\/v2)?\b/i,
162
- /\/wapi\/zpitem\/web\/boss\/[^?#]*\/geek\/info\b/i,
163
- /\/boss\/[^?#]*\/geek\/info\b/i,
164
- /\/geek\/info\b/i,
165
- /\/web\/frame\/c-resume\//i,
166
- /resume/i
167
- ]);
1
+ export const RECRUIT_TARGET_URL = "https://www.zhipin.com/web/chat/search";
2
+
3
+ export const RECRUIT_IFRAME_SELECTORS = Object.freeze([
4
+ 'iframe[name="searchFrame"]',
5
+ 'iframe[src*="/web/frame/search/"]',
6
+ "iframe"
7
+ ]);
8
+
9
+ export const RECRUIT_CARD_SELECTOR = [
10
+ "li.geek-info-card a[data-jid]",
11
+ "li.geek-info-card a[data-geekid]",
12
+ ".geek-info-card a[data-jid]",
13
+ ".geek-info-card a[data-geekid]",
14
+ ".geek-info-card a",
15
+ "a[data-jid]",
16
+ "a[data-geekid]"
17
+ ].join(", ");
18
+
19
+ export const RECRUIT_LIST_CONTAINER_SELECTORS = Object.freeze([
20
+ ".search-list",
21
+ ".search-result-list",
22
+ ".candidate-list",
23
+ ".geek-list",
24
+ ".geek-list-wrap",
25
+ ".card-list",
26
+ ".list-wrap",
27
+ ".search-content",
28
+ ".search-container"
29
+ ]);
30
+
31
+ export const RECRUIT_NO_DATA_SELECTORS = Object.freeze([
32
+ "i.tip-nodata",
33
+ ".tip-nodata",
34
+ ".empty-tip",
35
+ ".empty-text",
36
+ '[class*="empty"]'
37
+ ]);
38
+
39
+ export const RECRUIT_BOTTOM_MARKER_SELECTORS = Object.freeze([
40
+ ".finished-wrap",
41
+ ".loadmore",
42
+ ".load-tips",
43
+ ".tip-nodata",
44
+ ".empty-tip",
45
+ ".empty-text",
46
+ ".no-data",
47
+ "[class*=\"finished\"]",
48
+ "[class*=\"loadmore\"]",
49
+ "[class*=\"load-tips\"]",
50
+ "[class*=\"empty\"]"
51
+ ]);
52
+
53
+ export const RECRUIT_BOTTOM_REFRESH_SELECTORS = Object.freeze([
54
+ ".finished-wrap .btn-refresh",
55
+ ".finished-wrap .btn",
56
+ ".no-data-refresh .btn-refresh",
57
+ ".no-data-refresh .btn",
58
+ "[class*=\"refresh\"]",
59
+ "[ka*=\"refresh\"]",
60
+ "button",
61
+ "a"
62
+ ]);
63
+
64
+ export const RECRUIT_SEARCH_SELECTORS = Object.freeze({
65
+ keywordInput: [
66
+ "input.search-input",
67
+ ".search-box input",
68
+ ".search-wrap input",
69
+ 'input[placeholder*="搜索"]',
70
+ "input"
71
+ ],
72
+ searchButton: [
73
+ ".icon-search",
74
+ ".search-btn",
75
+ 'button[ka*="search"]',
76
+ '[class*="search"][class*="btn"]'
77
+ ],
78
+ jobTitleOption: [
79
+ '.search-job-list-C li[ka="search_select_job"]',
80
+ ".search-job-list-C li",
81
+ '[ka="search_select_job"]'
82
+ ],
83
+ degreeOption: [
84
+ ".degree-list-C .degree-item",
85
+ ".degree-list-C li",
86
+ ".degree-item",
87
+ '[ka*="degree"]'
88
+ ],
89
+ schoolItem: [
90
+ ".school-item",
91
+ ".school-list-C .school-item",
92
+ ".school-list-C li",
93
+ '[class*="school"][class*="item"]'
94
+ ],
95
+ schoolClickable: [
96
+ "label.checkbox",
97
+ "label",
98
+ ".checkbox",
99
+ ".checkbox-text"
100
+ ],
101
+ recentViewedLabel: [
102
+ 'label.checkbox.high_search_checkbox[ka="search_change_view_resume"]',
103
+ "label.checkbox.high_search_checkbox",
104
+ "label.checkbox",
105
+ '[ka="search_change_view_resume"]'
106
+ ],
107
+ cityInput: [
108
+ ".city-wrap .search-city-kw input",
109
+ ".search-city-kw input",
110
+ ".city-wrap input",
111
+ 'input[placeholder*="城市"]'
112
+ ],
113
+ citySearchResult: [
114
+ ".city-box .search-result-C .search-result-item",
115
+ ".search-result-C .search-result-item",
116
+ ".city-box li",
117
+ ".dropdown-city li"
118
+ ],
119
+ cityProvinceItem: [
120
+ ".dropdown-province li"
121
+ ],
122
+ cityDropdownItem: [
123
+ ".dropdown-city li"
124
+ ]
125
+ });
126
+
127
+ export const RECRUIT_DETAIL_POPUP_SELECTORS = Object.freeze([
128
+ ".dialog-wrap.active",
129
+ ".boss-popup__wrapper",
130
+ ".boss-popup_wrapper",
131
+ ".boss-dialog_wrapper",
132
+ ".boss-dialog",
133
+ ".resume-item-detail",
134
+ ".geek-detail-modal",
135
+ ".resume-container",
136
+ '[class*="popup"][class*="wrapper"]',
137
+ '[class*="dialog"][class*="wrapper"]'
138
+ ]);
139
+
140
+ export const RECRUIT_DETAIL_RESUME_IFRAME_SELECTORS = Object.freeze([
141
+ 'iframe[src*="/web/frame/c-resume/"]',
142
+ 'iframe[name*="resume"]'
143
+ ]);
144
+
145
+ export const RECRUIT_DETAIL_CLOSE_SELECTORS = Object.freeze([
146
+ ".boss-popup__close",
147
+ ".popup-close",
148
+ ".modal-close",
149
+ ".dialog-close",
150
+ ".close-btn",
151
+ 'button[aria-label*="关闭"]',
152
+ 'button[title*="关闭"]',
153
+ ".icon-close",
154
+ '[aria-label*="关闭"]',
155
+ '[title*="关闭"]',
156
+ '[class*="close"]'
157
+ ]);
158
+
159
+ export const RECRUIT_DETAIL_NETWORK_PATTERNS = Object.freeze([
160
+ /\/wapi\/zpitem\/web\/boss\/search\/geek\/info\b/i,
161
+ /\/wapi\/zpjob\/view\/geek\/info(?:\/v2)?\b/i,
162
+ /\/wapi\/zpitem\/web\/boss\/[^?#]*\/geek\/info\b/i,
163
+ /\/boss\/[^?#]*\/geek\/info\b/i,
164
+ /\/geek\/info\b/i,
165
+ /\/web\/frame\/c-resume\//i,
166
+ /resume/i
167
+ ]);