@reconcrap/boss-recommend-mcp 2.0.45 → 2.0.47

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 (56) 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 +1453 -1446
  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/screening/index.js +50 -3
  24. package/src/core/self-heal/index.js +973 -973
  25. package/src/core/self-heal/viewport.js +564 -564
  26. package/src/domains/chat/cards.js +137 -137
  27. package/src/domains/chat/constants.js +221 -221
  28. package/src/domains/chat/detail.js +1668 -1661
  29. package/src/domains/chat/index.js +7 -7
  30. package/src/domains/chat/jobs.js +592 -588
  31. package/src/domains/chat/page-guard.js +98 -98
  32. package/src/domains/chat/roots.js +56 -56
  33. package/src/domains/chat/run-service.js +1977 -1955
  34. package/src/domains/recommend/actions.js +457 -457
  35. package/src/domains/recommend/cards.js +243 -243
  36. package/src/domains/recommend/constants.js +165 -165
  37. package/src/domains/recommend/detail.js +36 -28
  38. package/src/domains/recommend/filters.js +610 -581
  39. package/src/domains/recommend/index.js +10 -10
  40. package/src/domains/recommend/jobs.js +316 -263
  41. package/src/domains/recommend/refresh.js +472 -472
  42. package/src/domains/recommend/roots.js +80 -80
  43. package/src/domains/recommend/run-service.js +75 -35
  44. package/src/domains/recommend/scopes.js +246 -245
  45. package/src/domains/recruit/actions.js +277 -277
  46. package/src/domains/recruit/cards.js +74 -74
  47. package/src/domains/recruit/constants.js +167 -167
  48. package/src/domains/recruit/detail.js +461 -460
  49. package/src/domains/recruit/index.js +9 -9
  50. package/src/domains/recruit/instruction-parser.js +451 -451
  51. package/src/domains/recruit/refresh.js +44 -44
  52. package/src/domains/recruit/roots.js +68 -68
  53. package/src/domains/recruit/run-service.js +1207 -1161
  54. package/src/domains/recruit/search.js +1202 -1149
  55. package/src/recommend-mcp.js +22 -22
  56. 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
+ ]);