@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,299 +1,299 @@
1
- import {
2
- getFrameDocumentNodeId,
3
- getNodeBox,
4
- querySelector,
5
- querySelectorAll,
6
- sleep
7
- } from "../browser/index.js";
8
-
9
- export const CV_CAPTURE_TARGET_SELECTORS = Object.freeze([
10
- ".resume-center-side .resume-detail-wrap",
11
- ".resume-container .resume-detail-wrap",
12
- ".resume-container .resume-content-wrap",
13
- ".resume-item-detail",
14
- ".resume-detail-wrap",
15
- ".resume-content-wrap",
16
- ".resume-common-wrap",
17
- ".new-resume-online-main-ui",
18
- ".resume-detail",
19
- ".resume-recommend",
20
- "canvas#resume",
21
- ".resume-container"
22
- ]);
23
-
24
- const IFRAME_BODY_SELECTORS = Object.freeze(["body", "html"]);
25
-
26
- function slotNodeId(slot = null) {
27
- return Number(slot?.node_id || slot?.nodeId || 0) || 0;
28
- }
29
-
30
- function rootNodeId(root = null) {
31
- return Number(root?.nodeId || root?.node_id || root?.root_node_id || 0) || 0;
32
- }
33
-
34
- function normalizeRootName(root = null, fallback = "") {
35
- return String(root?.name || root?.root || fallback || "").trim() || null;
36
- }
37
-
38
- function uniqueRoots(roots = []) {
39
- const seen = new Set();
40
- const result = [];
41
- for (const root of roots) {
42
- const nodeId = rootNodeId(root);
43
- if (!nodeId || seen.has(nodeId)) continue;
44
- seen.add(nodeId);
45
- result.push({
46
- ...root,
47
- name: normalizeRootName(root),
48
- nodeId
49
- });
50
- }
51
- return result;
52
- }
53
-
54
- function slotAsRoot(slot = null, fallbackName = "") {
55
- const nodeId = slotNodeId(slot);
56
- if (!nodeId) return null;
57
- return {
58
- name: normalizeRootName(slot, fallbackName),
59
- nodeId,
60
- selector: slot?.selector || null,
61
- root_node_id: slot?.root_node_id || null
62
- };
63
- }
64
-
65
- function isVisibleBox(box = null) {
66
- return box?.rect?.width > 2 && box?.rect?.height > 2;
67
- }
68
-
69
- async function readVisibleBox(client, nodeId) {
70
- if (!nodeId) return null;
71
- try {
72
- const box = await getNodeBox(client, nodeId);
73
- return isVisibleBox(box) ? box : null;
74
- } catch {
75
- return null;
76
- }
77
- }
78
-
79
- function isCvScopedSelector(selector = "") {
80
- const normalized = String(selector || "").trim();
81
- if (!normalized) return false;
82
- if (/boss-popup|boss-dialog|dialog-wrap|geek-detail-modal|\bmodal\b|new-chat-resume-dialog-main-ui/i.test(normalized)) {
83
- return false;
84
- }
85
- return /resume-item-detail|resume-detail-wrap|resume-content-wrap|resume-common-wrap|new-resume-online-main-ui|resume-detail(?:\b|[.#:])|resume-recommend|canvas#resume|resume-container/i.test(normalized);
86
- }
87
-
88
- function buildTarget({
89
- domain = "",
90
- nodeId,
91
- source,
92
- selector = null,
93
- root = null,
94
- rootNodeId = null,
95
- box = null,
96
- iframeNodeId = null,
97
- iframeDocumentNodeId = null,
98
- fallback = false
99
- } = {}) {
100
- return {
101
- schema_version: 1,
102
- domain: domain || null,
103
- node_id: nodeId,
104
- source,
105
- selector,
106
- root,
107
- root_node_id: rootNodeId || null,
108
- iframe_node_id: iframeNodeId || null,
109
- iframe_document_node_id: iframeDocumentNodeId || null,
110
- cv_only: !fallback,
111
- fallback: Boolean(fallback),
112
- rect: box?.rect || null,
113
- center: box?.center || null
114
- };
115
- }
116
-
117
- async function firstVisibleSelectorTarget(client, roots = [], selectors = CV_CAPTURE_TARGET_SELECTORS, {
118
- domain = "",
119
- source = "cv_selector",
120
- iframeNodeId = null,
121
- iframeDocumentNodeId = null
122
- } = {}) {
123
- for (const root of uniqueRoots(roots)) {
124
- for (const selector of selectors) {
125
- let nodeIds = [];
126
- try {
127
- nodeIds = await querySelectorAll(client, root.nodeId, selector);
128
- } catch {
129
- nodeIds = [];
130
- }
131
- for (const nodeId of nodeIds) {
132
- const box = await readVisibleBox(client, nodeId);
133
- if (!box) continue;
134
- return buildTarget({
135
- domain,
136
- nodeId,
137
- source,
138
- selector,
139
- root: root.name,
140
- rootNodeId: root.nodeId,
141
- box,
142
- iframeNodeId,
143
- iframeDocumentNodeId
144
- });
145
- }
146
- }
147
- }
148
- return null;
149
- }
150
-
151
- async function visibleSlotTarget(client, slot = null, {
152
- domain = "",
153
- source = "cv_slot",
154
- fallback = false
155
- } = {}) {
156
- const nodeId = slotNodeId(slot);
157
- if (!nodeId) return null;
158
- if (!fallback && !isCvScopedSelector(slot?.selector)) return null;
159
- const box = await readVisibleBox(client, nodeId);
160
- if (!box) return null;
161
- return buildTarget({
162
- domain,
163
- nodeId,
164
- source,
165
- selector: slot?.selector || null,
166
- root: slot?.root || null,
167
- rootNodeId: slot?.root_node_id || null,
168
- box,
169
- fallback
170
- });
171
- }
172
-
173
- async function resolveIframeCaptureTarget(client, resumeIframe = null, {
174
- domain = "",
175
- selectors = CV_CAPTURE_TARGET_SELECTORS
176
- } = {}) {
177
- const iframeNodeId = slotNodeId(resumeIframe);
178
- if (!iframeNodeId) return null;
179
-
180
- try {
181
- const documentNodeId = await getFrameDocumentNodeId(client, iframeNodeId);
182
- const selectorTarget = await firstVisibleSelectorTarget(client, [{
183
- name: "resume-iframe-document",
184
- nodeId: documentNodeId
185
- }], selectors, {
186
- domain,
187
- source: "resume_iframe_cv_selector",
188
- iframeNodeId,
189
- iframeDocumentNodeId: documentNodeId
190
- });
191
- if (selectorTarget) return selectorTarget;
192
-
193
- for (const selector of IFRAME_BODY_SELECTORS) {
194
- const nodeId = await querySelector(client, documentNodeId, selector).catch(() => 0);
195
- const box = await readVisibleBox(client, nodeId);
196
- if (!box) continue;
197
- return buildTarget({
198
- domain,
199
- nodeId,
200
- source: "resume_iframe_body",
201
- selector,
202
- root: "resume-iframe-document",
203
- rootNodeId: documentNodeId,
204
- box,
205
- iframeNodeId,
206
- iframeDocumentNodeId: documentNodeId
207
- });
208
- }
209
- } catch {}
210
-
211
- const iframeBox = await readVisibleBox(client, iframeNodeId);
212
- if (!iframeBox) return null;
213
- return buildTarget({
214
- domain,
215
- nodeId: iframeNodeId,
216
- source: "resume_iframe_element",
217
- selector: resumeIframe?.selector || null,
218
- root: resumeIframe?.root || null,
219
- rootNodeId: resumeIframe?.root_node_id || null,
220
- box: iframeBox,
221
- iframeNodeId,
222
- fallback: false
223
- });
224
- }
225
-
226
- async function resolveSlotCaptureTarget(client, slot = null, {
227
- domain = "",
228
- slotName = "content",
229
- selectors = CV_CAPTURE_TARGET_SELECTORS
230
- } = {}) {
231
- const root = slotAsRoot(slot, slotName);
232
- const selectorTarget = root
233
- ? await firstVisibleSelectorTarget(client, [root], selectors, {
234
- domain,
235
- source: `${slotName}_cv_selector`
236
- })
237
- : null;
238
- if (selectorTarget) return selectorTarget;
239
- return visibleSlotTarget(client, slot, {
240
- domain,
241
- source: `${slotName}_cv_slot`
242
- });
243
- }
244
-
245
- export async function resolveCvCaptureTarget(client, detailState = null, {
246
- domain = "",
247
- selectors = CV_CAPTURE_TARGET_SELECTORS
248
- } = {}) {
249
- const iframeTarget = await resolveIframeCaptureTarget(client, detailState?.resumeIframe, {
250
- domain,
251
- selectors
252
- });
253
- if (iframeTarget) return iframeTarget;
254
-
255
- const contentTarget = await resolveSlotCaptureTarget(client, detailState?.content, {
256
- domain,
257
- slotName: "content",
258
- selectors
259
- });
260
- if (contentTarget) return contentTarget;
261
-
262
- const popupTarget = await resolveSlotCaptureTarget(client, detailState?.popup, {
263
- domain,
264
- slotName: "popup",
265
- selectors
266
- });
267
- if (popupTarget) return popupTarget;
268
-
269
- return firstVisibleSelectorTarget(client, detailState?.roots || [], selectors, {
270
- domain,
271
- source: "root_cv_selector"
272
- });
273
- }
274
-
275
- export async function waitForCvCaptureTarget(client, detailState = null, {
276
- timeoutMs = 6000,
277
- intervalMs = 250,
278
- ...options
279
- } = {}) {
280
- const started = Date.now();
281
- let target = null;
282
- while (Date.now() - started <= Math.max(0, Number(timeoutMs) || 0)) {
283
- target = await resolveCvCaptureTarget(client, detailState, options);
284
- if (target?.node_id) {
285
- return {
286
- ok: true,
287
- elapsed_ms: Date.now() - started,
288
- target
289
- };
290
- }
291
- await sleep(Math.max(50, Number(intervalMs) || 250));
292
- }
293
- target = await resolveCvCaptureTarget(client, detailState, options);
294
- return {
295
- ok: Boolean(target?.node_id),
296
- elapsed_ms: Date.now() - started,
297
- target: target || null
298
- };
299
- }
1
+ import {
2
+ getFrameDocumentNodeId,
3
+ getNodeBox,
4
+ querySelector,
5
+ querySelectorAll,
6
+ sleep
7
+ } from "../browser/index.js";
8
+
9
+ export const CV_CAPTURE_TARGET_SELECTORS = Object.freeze([
10
+ ".resume-center-side .resume-detail-wrap",
11
+ ".resume-container .resume-detail-wrap",
12
+ ".resume-container .resume-content-wrap",
13
+ ".resume-item-detail",
14
+ ".resume-detail-wrap",
15
+ ".resume-content-wrap",
16
+ ".resume-common-wrap",
17
+ ".new-resume-online-main-ui",
18
+ ".resume-detail",
19
+ ".resume-recommend",
20
+ "canvas#resume",
21
+ ".resume-container"
22
+ ]);
23
+
24
+ const IFRAME_BODY_SELECTORS = Object.freeze(["body", "html"]);
25
+
26
+ function slotNodeId(slot = null) {
27
+ return Number(slot?.node_id || slot?.nodeId || 0) || 0;
28
+ }
29
+
30
+ function rootNodeId(root = null) {
31
+ return Number(root?.nodeId || root?.node_id || root?.root_node_id || 0) || 0;
32
+ }
33
+
34
+ function normalizeRootName(root = null, fallback = "") {
35
+ return String(root?.name || root?.root || fallback || "").trim() || null;
36
+ }
37
+
38
+ function uniqueRoots(roots = []) {
39
+ const seen = new Set();
40
+ const result = [];
41
+ for (const root of roots) {
42
+ const nodeId = rootNodeId(root);
43
+ if (!nodeId || seen.has(nodeId)) continue;
44
+ seen.add(nodeId);
45
+ result.push({
46
+ ...root,
47
+ name: normalizeRootName(root),
48
+ nodeId
49
+ });
50
+ }
51
+ return result;
52
+ }
53
+
54
+ function slotAsRoot(slot = null, fallbackName = "") {
55
+ const nodeId = slotNodeId(slot);
56
+ if (!nodeId) return null;
57
+ return {
58
+ name: normalizeRootName(slot, fallbackName),
59
+ nodeId,
60
+ selector: slot?.selector || null,
61
+ root_node_id: slot?.root_node_id || null
62
+ };
63
+ }
64
+
65
+ function isVisibleBox(box = null) {
66
+ return box?.rect?.width > 2 && box?.rect?.height > 2;
67
+ }
68
+
69
+ async function readVisibleBox(client, nodeId) {
70
+ if (!nodeId) return null;
71
+ try {
72
+ const box = await getNodeBox(client, nodeId);
73
+ return isVisibleBox(box) ? box : null;
74
+ } catch {
75
+ return null;
76
+ }
77
+ }
78
+
79
+ function isCvScopedSelector(selector = "") {
80
+ const normalized = String(selector || "").trim();
81
+ if (!normalized) return false;
82
+ if (/boss-popup|boss-dialog|dialog-wrap|geek-detail-modal|\bmodal\b|new-chat-resume-dialog-main-ui/i.test(normalized)) {
83
+ return false;
84
+ }
85
+ return /resume-item-detail|resume-detail-wrap|resume-content-wrap|resume-common-wrap|new-resume-online-main-ui|resume-detail(?:\b|[.#:])|resume-recommend|canvas#resume|resume-container/i.test(normalized);
86
+ }
87
+
88
+ function buildTarget({
89
+ domain = "",
90
+ nodeId,
91
+ source,
92
+ selector = null,
93
+ root = null,
94
+ rootNodeId = null,
95
+ box = null,
96
+ iframeNodeId = null,
97
+ iframeDocumentNodeId = null,
98
+ fallback = false
99
+ } = {}) {
100
+ return {
101
+ schema_version: 1,
102
+ domain: domain || null,
103
+ node_id: nodeId,
104
+ source,
105
+ selector,
106
+ root,
107
+ root_node_id: rootNodeId || null,
108
+ iframe_node_id: iframeNodeId || null,
109
+ iframe_document_node_id: iframeDocumentNodeId || null,
110
+ cv_only: !fallback,
111
+ fallback: Boolean(fallback),
112
+ rect: box?.rect || null,
113
+ center: box?.center || null
114
+ };
115
+ }
116
+
117
+ async function firstVisibleSelectorTarget(client, roots = [], selectors = CV_CAPTURE_TARGET_SELECTORS, {
118
+ domain = "",
119
+ source = "cv_selector",
120
+ iframeNodeId = null,
121
+ iframeDocumentNodeId = null
122
+ } = {}) {
123
+ for (const root of uniqueRoots(roots)) {
124
+ for (const selector of selectors) {
125
+ let nodeIds = [];
126
+ try {
127
+ nodeIds = await querySelectorAll(client, root.nodeId, selector);
128
+ } catch {
129
+ nodeIds = [];
130
+ }
131
+ for (const nodeId of nodeIds) {
132
+ const box = await readVisibleBox(client, nodeId);
133
+ if (!box) continue;
134
+ return buildTarget({
135
+ domain,
136
+ nodeId,
137
+ source,
138
+ selector,
139
+ root: root.name,
140
+ rootNodeId: root.nodeId,
141
+ box,
142
+ iframeNodeId,
143
+ iframeDocumentNodeId
144
+ });
145
+ }
146
+ }
147
+ }
148
+ return null;
149
+ }
150
+
151
+ async function visibleSlotTarget(client, slot = null, {
152
+ domain = "",
153
+ source = "cv_slot",
154
+ fallback = false
155
+ } = {}) {
156
+ const nodeId = slotNodeId(slot);
157
+ if (!nodeId) return null;
158
+ if (!fallback && !isCvScopedSelector(slot?.selector)) return null;
159
+ const box = await readVisibleBox(client, nodeId);
160
+ if (!box) return null;
161
+ return buildTarget({
162
+ domain,
163
+ nodeId,
164
+ source,
165
+ selector: slot?.selector || null,
166
+ root: slot?.root || null,
167
+ rootNodeId: slot?.root_node_id || null,
168
+ box,
169
+ fallback
170
+ });
171
+ }
172
+
173
+ async function resolveIframeCaptureTarget(client, resumeIframe = null, {
174
+ domain = "",
175
+ selectors = CV_CAPTURE_TARGET_SELECTORS
176
+ } = {}) {
177
+ const iframeNodeId = slotNodeId(resumeIframe);
178
+ if (!iframeNodeId) return null;
179
+
180
+ try {
181
+ const documentNodeId = await getFrameDocumentNodeId(client, iframeNodeId);
182
+ const selectorTarget = await firstVisibleSelectorTarget(client, [{
183
+ name: "resume-iframe-document",
184
+ nodeId: documentNodeId
185
+ }], selectors, {
186
+ domain,
187
+ source: "resume_iframe_cv_selector",
188
+ iframeNodeId,
189
+ iframeDocumentNodeId: documentNodeId
190
+ });
191
+ if (selectorTarget) return selectorTarget;
192
+
193
+ for (const selector of IFRAME_BODY_SELECTORS) {
194
+ const nodeId = await querySelector(client, documentNodeId, selector).catch(() => 0);
195
+ const box = await readVisibleBox(client, nodeId);
196
+ if (!box) continue;
197
+ return buildTarget({
198
+ domain,
199
+ nodeId,
200
+ source: "resume_iframe_body",
201
+ selector,
202
+ root: "resume-iframe-document",
203
+ rootNodeId: documentNodeId,
204
+ box,
205
+ iframeNodeId,
206
+ iframeDocumentNodeId: documentNodeId
207
+ });
208
+ }
209
+ } catch {}
210
+
211
+ const iframeBox = await readVisibleBox(client, iframeNodeId);
212
+ if (!iframeBox) return null;
213
+ return buildTarget({
214
+ domain,
215
+ nodeId: iframeNodeId,
216
+ source: "resume_iframe_element",
217
+ selector: resumeIframe?.selector || null,
218
+ root: resumeIframe?.root || null,
219
+ rootNodeId: resumeIframe?.root_node_id || null,
220
+ box: iframeBox,
221
+ iframeNodeId,
222
+ fallback: false
223
+ });
224
+ }
225
+
226
+ async function resolveSlotCaptureTarget(client, slot = null, {
227
+ domain = "",
228
+ slotName = "content",
229
+ selectors = CV_CAPTURE_TARGET_SELECTORS
230
+ } = {}) {
231
+ const root = slotAsRoot(slot, slotName);
232
+ const selectorTarget = root
233
+ ? await firstVisibleSelectorTarget(client, [root], selectors, {
234
+ domain,
235
+ source: `${slotName}_cv_selector`
236
+ })
237
+ : null;
238
+ if (selectorTarget) return selectorTarget;
239
+ return visibleSlotTarget(client, slot, {
240
+ domain,
241
+ source: `${slotName}_cv_slot`
242
+ });
243
+ }
244
+
245
+ export async function resolveCvCaptureTarget(client, detailState = null, {
246
+ domain = "",
247
+ selectors = CV_CAPTURE_TARGET_SELECTORS
248
+ } = {}) {
249
+ const iframeTarget = await resolveIframeCaptureTarget(client, detailState?.resumeIframe, {
250
+ domain,
251
+ selectors
252
+ });
253
+ if (iframeTarget) return iframeTarget;
254
+
255
+ const contentTarget = await resolveSlotCaptureTarget(client, detailState?.content, {
256
+ domain,
257
+ slotName: "content",
258
+ selectors
259
+ });
260
+ if (contentTarget) return contentTarget;
261
+
262
+ const popupTarget = await resolveSlotCaptureTarget(client, detailState?.popup, {
263
+ domain,
264
+ slotName: "popup",
265
+ selectors
266
+ });
267
+ if (popupTarget) return popupTarget;
268
+
269
+ return firstVisibleSelectorTarget(client, detailState?.roots || [], selectors, {
270
+ domain,
271
+ source: "root_cv_selector"
272
+ });
273
+ }
274
+
275
+ export async function waitForCvCaptureTarget(client, detailState = null, {
276
+ timeoutMs = 6000,
277
+ intervalMs = 250,
278
+ ...options
279
+ } = {}) {
280
+ const started = Date.now();
281
+ let target = null;
282
+ while (Date.now() - started <= Math.max(0, Number(timeoutMs) || 0)) {
283
+ target = await resolveCvCaptureTarget(client, detailState, options);
284
+ if (target?.node_id) {
285
+ return {
286
+ ok: true,
287
+ elapsed_ms: Date.now() - started,
288
+ target
289
+ };
290
+ }
291
+ await sleep(Math.max(50, Number(intervalMs) || 250));
292
+ }
293
+ target = await resolveCvCaptureTarget(client, detailState, options);
294
+ return {
295
+ ok: Boolean(target?.node_id),
296
+ elapsed_ms: Date.now() - started,
297
+ target: target || null
298
+ };
299
+ }