@reconcrap/boss-recommend-mcp 1.3.39 → 2.0.1

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 (88) hide show
  1. package/README.md +86 -33
  2. package/package.json +62 -9
  3. package/skills/boss-chat/SKILL.md +5 -4
  4. package/skills/boss-recommend-pipeline/SKILL.md +21 -31
  5. package/skills/boss-recruit-pipeline/README.md +17 -0
  6. package/skills/boss-recruit-pipeline/SKILL.md +55 -0
  7. package/src/chat-mcp.js +1333 -0
  8. package/src/chat-runtime-config.js +559 -0
  9. package/src/cli.js +1254 -225
  10. package/src/core/browser/index.js +378 -0
  11. package/src/core/capture/index.js +298 -0
  12. package/src/core/cv-acquisition/index.js +219 -0
  13. package/src/core/greet-quota/index.js +54 -0
  14. package/src/core/infinite-list/index.js +459 -0
  15. package/src/core/reporting/legacy-csv.js +332 -0
  16. package/src/core/run/index.js +286 -0
  17. package/src/core/screening/index.js +1166 -0
  18. package/src/core/self-heal/index.js +848 -0
  19. package/src/domains/chat/cards.js +129 -0
  20. package/src/domains/chat/constants.js +183 -0
  21. package/src/domains/chat/detail.js +1369 -0
  22. package/src/domains/chat/index.js +7 -0
  23. package/src/domains/chat/jobs.js +334 -0
  24. package/src/domains/chat/page-guard.js +88 -0
  25. package/src/domains/chat/roots.js +56 -0
  26. package/src/domains/chat/run-service.js +1101 -0
  27. package/src/domains/recommend/actions.js +457 -0
  28. package/src/domains/recommend/cards.js +228 -0
  29. package/src/domains/recommend/constants.js +141 -0
  30. package/src/domains/recommend/detail.js +341 -0
  31. package/src/domains/recommend/filters.js +581 -0
  32. package/src/domains/recommend/index.js +10 -0
  33. package/src/domains/recommend/jobs.js +232 -0
  34. package/src/domains/recommend/refresh.js +204 -0
  35. package/src/domains/recommend/roots.js +78 -0
  36. package/src/domains/recommend/run-service.js +903 -0
  37. package/src/domains/recommend/scopes.js +245 -0
  38. package/src/domains/recruit/actions.js +277 -0
  39. package/src/domains/recruit/cards.js +66 -0
  40. package/src/domains/recruit/constants.js +130 -0
  41. package/src/domains/recruit/detail.js +414 -0
  42. package/src/domains/recruit/index.js +9 -0
  43. package/src/domains/recruit/instruction-parser.js +451 -0
  44. package/src/domains/recruit/refresh.js +40 -0
  45. package/src/domains/recruit/roots.js +67 -0
  46. package/src/domains/recruit/run-service.js +580 -0
  47. package/src/domains/recruit/search.js +1149 -0
  48. package/src/index.js +578 -419
  49. package/src/recommend-mcp.js +1257 -0
  50. package/src/recruit-mcp.js +1035 -0
  51. package/src/adapters.js +0 -3079
  52. package/src/boss-chat.js +0 -1037
  53. package/src/pipeline.js +0 -2249
  54. package/src/recommend-healing-config.js +0 -131
  55. package/src/recommend-healing-rules.json +0 -261
  56. package/src/self-heal.js +0 -2237
  57. package/src/test-adapters-runtime.js +0 -628
  58. package/src/test-boss-chat.js +0 -3196
  59. package/src/test-index-async.js +0 -498
  60. package/src/test-parser.js +0 -742
  61. package/src/test-pipeline.js +0 -2703
  62. package/src/test-run-state.js +0 -152
  63. package/src/test-self-heal.js +0 -224
  64. package/vendor/boss-chat-cli/README.md +0 -134
  65. package/vendor/boss-chat-cli/package.json +0 -53
  66. package/vendor/boss-chat-cli/src/app.js +0 -1501
  67. package/vendor/boss-chat-cli/src/browser/chat-page.js +0 -3562
  68. package/vendor/boss-chat-cli/src/cli.js +0 -1713
  69. package/vendor/boss-chat-cli/src/mcp/server.js +0 -149
  70. package/vendor/boss-chat-cli/src/mcp/tool-runtime.js +0 -193
  71. package/vendor/boss-chat-cli/src/runtime/async-run-state.js +0 -260
  72. package/vendor/boss-chat-cli/src/runtime/interaction.js +0 -102
  73. package/vendor/boss-chat-cli/src/runtime/run-control.js +0 -102
  74. package/vendor/boss-chat-cli/src/services/chrome-client.js +0 -107
  75. package/vendor/boss-chat-cli/src/services/llm.js +0 -1292
  76. package/vendor/boss-chat-cli/src/services/llm.test.js +0 -326
  77. package/vendor/boss-chat-cli/src/services/profile-store.js +0 -173
  78. package/vendor/boss-chat-cli/src/services/report-store.js +0 -317
  79. package/vendor/boss-chat-cli/src/services/resume-capture.js +0 -469
  80. package/vendor/boss-chat-cli/src/services/resume-network.js +0 -727
  81. package/vendor/boss-chat-cli/src/services/state-store.js +0 -90
  82. package/vendor/boss-chat-cli/src/utils/customer-key.js +0 -82
  83. package/vendor/boss-recommend-screen-cli/boss-recommend-screen-cli.cjs +0 -7072
  84. package/vendor/boss-recommend-screen-cli/scripts/capture-full-resume-canvas.cjs +0 -817
  85. package/vendor/boss-recommend-screen-cli/scripts/stitch_resume_chunks.py +0 -141
  86. package/vendor/boss-recommend-screen-cli/test-recoverable-resume-failures.cjs +0 -2423
  87. package/vendor/boss-recommend-search-cli/src/cli.js +0 -1698
  88. package/vendor/boss-recommend-search-cli/src/test-job-selection.js +0 -211
@@ -0,0 +1,130 @@
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_NO_DATA_SELECTORS = Object.freeze([
20
+ "i.tip-nodata",
21
+ ".tip-nodata",
22
+ ".empty-tip",
23
+ ".empty-text",
24
+ '[class*="empty"]'
25
+ ]);
26
+
27
+ export const RECRUIT_SEARCH_SELECTORS = Object.freeze({
28
+ keywordInput: [
29
+ "input.search-input",
30
+ ".search-box input",
31
+ ".search-wrap input",
32
+ 'input[placeholder*="搜索"]',
33
+ "input"
34
+ ],
35
+ searchButton: [
36
+ ".icon-search",
37
+ ".search-btn",
38
+ 'button[ka*="search"]',
39
+ '[class*="search"][class*="btn"]'
40
+ ],
41
+ jobTitleOption: [
42
+ '.search-job-list-C li[ka="search_select_job"]',
43
+ ".search-job-list-C li",
44
+ '[ka="search_select_job"]'
45
+ ],
46
+ degreeOption: [
47
+ ".degree-list-C .degree-item",
48
+ ".degree-list-C li",
49
+ ".degree-item",
50
+ '[ka*="degree"]'
51
+ ],
52
+ schoolItem: [
53
+ ".school-item",
54
+ ".school-list-C .school-item",
55
+ ".school-list-C li",
56
+ '[class*="school"][class*="item"]'
57
+ ],
58
+ schoolClickable: [
59
+ "label.checkbox",
60
+ "label",
61
+ ".checkbox",
62
+ ".checkbox-text"
63
+ ],
64
+ recentViewedLabel: [
65
+ 'label.checkbox.high_search_checkbox[ka="search_change_view_resume"]',
66
+ "label.checkbox.high_search_checkbox",
67
+ "label.checkbox",
68
+ '[ka="search_change_view_resume"]'
69
+ ],
70
+ cityInput: [
71
+ ".city-wrap .search-city-kw input",
72
+ ".search-city-kw input",
73
+ ".city-wrap input",
74
+ 'input[placeholder*="城市"]'
75
+ ],
76
+ citySearchResult: [
77
+ ".city-box .search-result-C .search-result-item",
78
+ ".search-result-C .search-result-item",
79
+ ".city-box li",
80
+ ".dropdown-city li"
81
+ ],
82
+ cityProvinceItem: [
83
+ ".dropdown-province li"
84
+ ],
85
+ cityDropdownItem: [
86
+ ".dropdown-city li"
87
+ ]
88
+ });
89
+
90
+ export const RECRUIT_DETAIL_POPUP_SELECTORS = Object.freeze([
91
+ ".dialog-wrap.active",
92
+ ".boss-popup__wrapper",
93
+ ".boss-popup_wrapper",
94
+ ".boss-dialog_wrapper",
95
+ ".boss-dialog",
96
+ ".resume-item-detail",
97
+ ".geek-detail-modal",
98
+ ".resume-container",
99
+ '[class*="popup"][class*="wrapper"]',
100
+ '[class*="dialog"][class*="wrapper"]'
101
+ ]);
102
+
103
+ export const RECRUIT_DETAIL_RESUME_IFRAME_SELECTORS = Object.freeze([
104
+ 'iframe[src*="/web/frame/c-resume/"]',
105
+ 'iframe[name*="resume"]'
106
+ ]);
107
+
108
+ export const RECRUIT_DETAIL_CLOSE_SELECTORS = Object.freeze([
109
+ ".boss-popup__close",
110
+ ".popup-close",
111
+ ".modal-close",
112
+ ".dialog-close",
113
+ ".close-btn",
114
+ 'button[aria-label*="关闭"]',
115
+ 'button[title*="关闭"]',
116
+ ".icon-close",
117
+ '[aria-label*="关闭"]',
118
+ '[title*="关闭"]',
119
+ '[class*="close"]'
120
+ ]);
121
+
122
+ export const RECRUIT_DETAIL_NETWORK_PATTERNS = Object.freeze([
123
+ /\/wapi\/zpitem\/web\/boss\/search\/geek\/info\b/i,
124
+ /\/wapi\/zpjob\/view\/geek\/info(?:\/v2)?\b/i,
125
+ /\/wapi\/zpitem\/web\/boss\/[^?#]*\/geek\/info\b/i,
126
+ /\/boss\/[^?#]*\/geek\/info\b/i,
127
+ /\/geek\/info\b/i,
128
+ /\/web\/frame\/c-resume\//i,
129
+ /resume/i
130
+ ]);
@@ -0,0 +1,414 @@
1
+ import {
2
+ clickNodeCenter,
3
+ clickPoint,
4
+ getFrameDocumentNodeId,
5
+ getNodeBox,
6
+ getOuterHTML,
7
+ pressKey,
8
+ querySelectorAll,
9
+ sleep
10
+ } from "../../core/browser/index.js";
11
+ import {
12
+ buildScreeningCandidateFromDetail,
13
+ htmlToText
14
+ } from "../../core/screening/index.js";
15
+ import {
16
+ RECRUIT_DETAIL_CLOSE_SELECTORS,
17
+ RECRUIT_DETAIL_NETWORK_PATTERNS,
18
+ RECRUIT_DETAIL_POPUP_SELECTORS,
19
+ RECRUIT_DETAIL_RESUME_IFRAME_SELECTORS
20
+ } from "./constants.js";
21
+ import {
22
+ getRecruitRoots,
23
+ queryFirstAcrossRoots
24
+ } from "./roots.js";
25
+
26
+ export function matchesRecruitDetailNetwork(url) {
27
+ return RECRUIT_DETAIL_NETWORK_PATTERNS.some((pattern) => pattern.test(String(url || "")));
28
+ }
29
+
30
+ export function createRecruitDetailNetworkRecorder(client) {
31
+ const events = [];
32
+ client.Network.responseReceived((event) => {
33
+ const url = event?.response?.url || "";
34
+ if (!matchesRecruitDetailNetwork(url)) return;
35
+ events.push({
36
+ requestId: event.requestId,
37
+ url,
38
+ status: event.response?.status,
39
+ mimeType: event.response?.mimeType,
40
+ type: event.type
41
+ });
42
+ });
43
+ if (typeof client.Network.loadingFinished === "function") {
44
+ client.Network.loadingFinished((event) => {
45
+ const found = events.find((item) => item.requestId === event.requestId);
46
+ if (!found) return;
47
+ found.loading_finished = true;
48
+ found.encodedDataLength = event.encodedDataLength;
49
+ });
50
+ }
51
+ if (typeof client.Network.loadingFailed === "function") {
52
+ client.Network.loadingFailed((event) => {
53
+ const found = events.find((item) => item.requestId === event.requestId);
54
+ if (!found) return;
55
+ found.loading_failed = true;
56
+ found.loading_error = event.errorText || event.blockedReason || "Network loading failed";
57
+ });
58
+ }
59
+ return {
60
+ events,
61
+ clear() {
62
+ events.length = 0;
63
+ }
64
+ };
65
+ }
66
+
67
+ export async function waitForRecruitDetailNetworkEvents(recorder, {
68
+ minCount = 1,
69
+ requireLoaded = true,
70
+ timeoutMs = 3500,
71
+ intervalMs = 100
72
+ } = {}) {
73
+ const started = Date.now();
74
+ const events = Array.isArray(recorder) ? recorder : recorder?.events || [];
75
+ let matching = [];
76
+ while (Date.now() - started <= timeoutMs) {
77
+ matching = events.filter((event) => (
78
+ !requireLoaded
79
+ || event.loading_finished === true
80
+ || event.loading_failed === true
81
+ ));
82
+ if (matching.length >= minCount) {
83
+ return {
84
+ ok: true,
85
+ elapsed_ms: Date.now() - started,
86
+ count: matching.length,
87
+ events: matching
88
+ };
89
+ }
90
+ await sleep(intervalMs);
91
+ }
92
+ return {
93
+ ok: false,
94
+ elapsed_ms: Date.now() - started,
95
+ count: matching.length,
96
+ events: matching,
97
+ total_event_count: events.length
98
+ };
99
+ }
100
+
101
+ export async function readRecruitDetailNetworkBodies(client, events = [], {
102
+ limit = 10
103
+ } = {}) {
104
+ const bodies = [];
105
+ for (const event of events.slice(0, limit)) {
106
+ try {
107
+ const body = await client.Network.getResponseBody({ requestId: event.requestId });
108
+ bodies.push({
109
+ ...event,
110
+ body,
111
+ body_length: String(body?.body || "").length
112
+ });
113
+ } catch (error) {
114
+ bodies.push({
115
+ ...event,
116
+ body_error: error?.message || String(error)
117
+ });
118
+ }
119
+ }
120
+ return bodies;
121
+ }
122
+
123
+ export async function waitForRecruitDetail(client, {
124
+ timeoutMs = 12000,
125
+ intervalMs = 250
126
+ } = {}) {
127
+ const started = Date.now();
128
+ let lastState = null;
129
+ while (Date.now() - started <= timeoutMs) {
130
+ const rootState = await getRecruitRoots(client);
131
+ const popup = await queryFirstAcrossRoots(client, rootState.roots, RECRUIT_DETAIL_POPUP_SELECTORS);
132
+ const resumeIframe = await queryFirstAcrossRoots(client, rootState.roots, RECRUIT_DETAIL_RESUME_IFRAME_SELECTORS);
133
+ lastState = {
134
+ iframe: rootState.iframe,
135
+ roots: rootState.roots,
136
+ popup,
137
+ resumeIframe
138
+ };
139
+ if (popup || resumeIframe) return lastState;
140
+ await sleep(intervalMs);
141
+ }
142
+ return lastState;
143
+ }
144
+
145
+ export async function readRecruitDetailHtml(client, detailState) {
146
+ let popupHTML = "";
147
+ let resumeHTML = "";
148
+ let resumeIframeDocumentNodeId = null;
149
+
150
+ if (detailState?.popup?.node_id) {
151
+ popupHTML = await getOuterHTML(client, detailState.popup.node_id);
152
+ }
153
+
154
+ if (detailState?.resumeIframe?.node_id) {
155
+ resumeIframeDocumentNodeId = await getFrameDocumentNodeId(client, detailState.resumeIframe.node_id);
156
+ resumeHTML = await getOuterHTML(client, resumeIframeDocumentNodeId);
157
+ }
158
+
159
+ return {
160
+ popupHTML,
161
+ resumeHTML,
162
+ resumeIframeDocumentNodeId,
163
+ popupText: htmlToText(popupHTML),
164
+ resumeText: htmlToText(resumeHTML)
165
+ };
166
+ }
167
+
168
+ export async function waitForRecruitDetailContent(client, {
169
+ minTextLength = 200,
170
+ timeoutMs = 6000,
171
+ intervalMs = 200
172
+ } = {}) {
173
+ const started = Date.now();
174
+ let lastState = null;
175
+ let lastHtml = null;
176
+ let lastError = null;
177
+ while (Date.now() - started <= timeoutMs) {
178
+ try {
179
+ lastState = await waitForRecruitDetail(client, {
180
+ timeoutMs: 500,
181
+ intervalMs: 100
182
+ });
183
+ if (lastState?.popup || lastState?.resumeIframe) {
184
+ lastHtml = await readRecruitDetailHtml(client, lastState);
185
+ const textLength = (lastHtml.popupText || "").length + (lastHtml.resumeText || "").length;
186
+ if (textLength >= minTextLength) {
187
+ return {
188
+ ok: true,
189
+ elapsed_ms: Date.now() - started,
190
+ text_length: textLength,
191
+ detail_state: lastState,
192
+ detail_html: lastHtml
193
+ };
194
+ }
195
+ }
196
+ } catch (error) {
197
+ lastError = error;
198
+ }
199
+ await sleep(intervalMs);
200
+ }
201
+
202
+ const textLength = (lastHtml?.popupText || "").length + (lastHtml?.resumeText || "").length;
203
+ return {
204
+ ok: false,
205
+ elapsed_ms: Date.now() - started,
206
+ text_length: textLength,
207
+ detail_state: lastState,
208
+ detail_html: lastHtml,
209
+ error: lastError?.message || null
210
+ };
211
+ }
212
+
213
+ export async function openRecruitCardDetail(client, cardNodeId, {
214
+ timeoutMs = 12000
215
+ } = {}) {
216
+ const attempts = [];
217
+ const cardBox = await clickNodeCenter(client, cardNodeId, {
218
+ scrollIntoView: true
219
+ });
220
+ attempts.push({
221
+ mode: "card-center",
222
+ center: cardBox.center
223
+ });
224
+ let detailState = await waitForRecruitDetail(client, { timeoutMs });
225
+
226
+ if (!detailState?.popup && !detailState?.resumeIframe) {
227
+ const leftTitlePoint = {
228
+ x: cardBox.rect.x + Math.min(140, Math.max(40, cardBox.rect.width * 0.2)),
229
+ y: cardBox.rect.y + Math.min(42, Math.max(24, cardBox.rect.height * 0.28))
230
+ };
231
+ await clickPoint(client, leftTitlePoint.x, leftTitlePoint.y, {
232
+ clickCount: 2,
233
+ delayMs: 120
234
+ });
235
+ attempts.push({
236
+ mode: "card-left-title-double-click",
237
+ center: leftTitlePoint
238
+ });
239
+ detailState = await waitForRecruitDetail(client, {
240
+ timeoutMs: Math.max(3000, Math.floor(timeoutMs / 2))
241
+ });
242
+ }
243
+
244
+ if (!detailState?.popup && !detailState?.resumeIframe) {
245
+ throw new Error("Recruit candidate detail did not open or no known detail selectors mounted");
246
+ }
247
+
248
+ return {
249
+ card_box: cardBox,
250
+ open_attempts: attempts,
251
+ detail_state: detailState
252
+ };
253
+ }
254
+
255
+ export async function closeRecruitDetail(client, {
256
+ attemptsLimit = 3
257
+ } = {}) {
258
+ const attempts = [];
259
+ for (let index = 0; index < attemptsLimit; index += 1) {
260
+ const existingState = await waitForRecruitDetail(client, { timeoutMs: 500 });
261
+ if (!existingState?.popup && !existingState?.resumeIframe) {
262
+ return {
263
+ closed: true,
264
+ attempts
265
+ };
266
+ }
267
+
268
+ const rootState = await getRecruitRoots(client);
269
+ const closeTarget = await findVisibleCloseTarget(client, rootState.roots, RECRUIT_DETAIL_CLOSE_SELECTORS);
270
+ if (closeTarget) {
271
+ try {
272
+ if (closeTarget.center) {
273
+ await clickPoint(client, closeTarget.center.x, closeTarget.center.y);
274
+ } else {
275
+ await clickNodeCenter(client, closeTarget.node_id);
276
+ }
277
+ attempts.push({
278
+ mode: "close-selector",
279
+ selector: closeTarget.selector,
280
+ root: closeTarget.root
281
+ });
282
+ } catch (error) {
283
+ attempts.push({
284
+ mode: "close-selector-error",
285
+ selector: closeTarget.selector,
286
+ root: closeTarget.root,
287
+ error: error?.message || String(error)
288
+ });
289
+ await pressEscape(client);
290
+ attempts.push({ mode: "Escape-after-close-selector-error" });
291
+ }
292
+ await sleep(700);
293
+ } else {
294
+ await pressEscape(client);
295
+ attempts.push({ mode: "Escape" });
296
+ await sleep(700);
297
+ }
298
+
299
+ let state = await waitForRecruitDetail(client, { timeoutMs: 1000 });
300
+ if (!state?.popup && !state?.resumeIframe) {
301
+ return {
302
+ closed: true,
303
+ attempts
304
+ };
305
+ }
306
+
307
+ await pressEscape(client);
308
+ attempts.push({ mode: "Escape-fallback" });
309
+ await sleep(700);
310
+
311
+ state = await waitForRecruitDetail(client, { timeoutMs: 1000 });
312
+ if (!state?.popup && !state?.resumeIframe) {
313
+ return {
314
+ closed: true,
315
+ attempts
316
+ };
317
+ }
318
+ }
319
+
320
+ return {
321
+ closed: false,
322
+ attempts
323
+ };
324
+ }
325
+
326
+ async function findVisibleCloseTarget(client, roots, selectors) {
327
+ let fallback = null;
328
+ for (const root of roots) {
329
+ if (!root?.nodeId) continue;
330
+ for (const selector of selectors) {
331
+ const nodeIds = await querySelectorAll(client, root.nodeId, selector);
332
+ for (const nodeId of nodeIds) {
333
+ const target = {
334
+ root: root.name,
335
+ root_node_id: root.nodeId,
336
+ selector,
337
+ node_id: nodeId
338
+ };
339
+ if (!fallback) fallback = target;
340
+ try {
341
+ const box = await getNodeBox(client, nodeId);
342
+ if (box.rect.width > 2 && box.rect.height > 2) {
343
+ return {
344
+ ...target,
345
+ center: box.center,
346
+ rect: box.rect
347
+ };
348
+ }
349
+ } catch {}
350
+ }
351
+ }
352
+ }
353
+ return fallback;
354
+ }
355
+
356
+ async function pressEscape(client) {
357
+ await pressKey(client, "Escape", {
358
+ code: "Escape",
359
+ windowsVirtualKeyCode: 27,
360
+ nativeVirtualKeyCode: 27
361
+ });
362
+ }
363
+
364
+ export async function extractRecruitDetailCandidate(client, {
365
+ cardCandidate,
366
+ cardNodeId,
367
+ detailState,
368
+ detailHtml: providedDetailHtml = null,
369
+ networkEvents = [],
370
+ targetUrl = "",
371
+ closeDetail = true
372
+ } = {}) {
373
+ await sleep(1000);
374
+ const networkBodies = await readRecruitDetailNetworkBodies(client, networkEvents);
375
+ const detailHtml = providedDetailHtml || await readRecruitDetailHtml(client, detailState);
376
+ const detailText = [
377
+ detailHtml.popupText,
378
+ detailHtml.resumeText
379
+ ].filter(Boolean).join("\n\n");
380
+
381
+ const detailCandidateResult = buildScreeningCandidateFromDetail({
382
+ domain: "recruit",
383
+ cardCandidate,
384
+ detailText,
385
+ networkBodies,
386
+ metadata: {
387
+ target_url: targetUrl,
388
+ card_node_id: cardNodeId,
389
+ detail_popup_selector: detailState?.popup?.selector || null,
390
+ detail_popup_root: detailState?.popup?.root || null,
391
+ resume_iframe_selector: detailState?.resumeIframe?.selector || null,
392
+ resume_iframe_root: detailState?.resumeIframe?.root || null,
393
+ resume_iframe_document_node_id: detailHtml.resumeIframeDocumentNodeId
394
+ }
395
+ });
396
+
397
+ let closeResult = null;
398
+ if (closeDetail) {
399
+ closeResult = await closeRecruitDetail(client);
400
+ }
401
+
402
+ return {
403
+ candidate: detailCandidateResult.candidate,
404
+ parsed_network_profiles: detailCandidateResult.parsed_network_profiles,
405
+ network_bodies: networkBodies,
406
+ detail: {
407
+ popup_text: detailHtml.popupText,
408
+ resume_text: detailHtml.resumeText,
409
+ popup_html_length: detailHtml.popupHTML.length,
410
+ resume_html_length: detailHtml.resumeHTML.length
411
+ },
412
+ close_result: closeResult
413
+ };
414
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./constants.js";
2
+ export * from "./roots.js";
3
+ export * from "./cards.js";
4
+ export * from "./detail.js";
5
+ export * from "./actions.js";
6
+ export * from "./instruction-parser.js";
7
+ export * from "./search.js";
8
+ export * from "./refresh.js";
9
+ export * from "./run-service.js";