@reconcrap/boss-recommend-mcp 2.1.15 → 2.1.16
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 +29 -0
- package/package.json +8 -7
- package/src/chat-mcp.js +57 -15
- package/src/core/greet-quota/index.js +17 -0
- package/src/core/reporting/legacy-csv.js +5 -1
- package/src/domains/recommend/colleague-contact.js +333 -0
- package/src/domains/recommend/index.js +1 -0
- package/src/domains/recommend/run-service.js +166 -77
- package/src/domains/recruit/constants.js +4 -0
- package/src/domains/recruit/instruction-parser.js +42 -1
- package/src/domains/recruit/run-service.js +42 -4
- package/src/domains/recruit/search.js +40 -6
- package/src/index.js +20 -11
- package/src/parser.js +45 -2
- package/src/recommend-mcp.js +15 -10
- package/src/recruit-mcp.js +8 -0
|
@@ -699,7 +699,8 @@ export function normalizeRecruitSearchParams(searchParams = {}) {
|
|
|
699
699
|
keyword: normalizeText(searchParams.keyword) || DEFAULT_RECRUIT_KEYWORD,
|
|
700
700
|
filter_recent_viewed: typeof searchParams.filter_recent_viewed === "boolean"
|
|
701
701
|
? searchParams.filter_recent_viewed
|
|
702
|
-
: null
|
|
702
|
+
: null,
|
|
703
|
+
skip_recent_colleague_contacted: searchParams.skip_recent_colleague_contacted !== false
|
|
703
704
|
};
|
|
704
705
|
const job = normalizeText(searchParams.job || searchParams.job_title || searchParams.selected_job);
|
|
705
706
|
if (job) normalized.job = job;
|
|
@@ -720,6 +721,7 @@ export function buildRecruitSearchApplicationStepNames(searchParams = {}) {
|
|
|
720
721
|
if (normalized.gender) steps.push("gender");
|
|
721
722
|
if (normalized.age) steps.push("age");
|
|
722
723
|
if (typeof normalized.filter_recent_viewed === "boolean") steps.push("recent_viewed");
|
|
724
|
+
if (typeof normalized.skip_recent_colleague_contacted === "boolean") steps.push("exchange_resume");
|
|
723
725
|
// Keyword is the final filter before executing the search.
|
|
724
726
|
steps.push("keyword", "search");
|
|
725
727
|
return steps;
|
|
@@ -739,7 +741,8 @@ export function hasRecruitSearchParams(searchParams = {}) {
|
|
|
739
741
|
keyword: normalizeText(searchParams.keyword),
|
|
740
742
|
filter_recent_viewed: typeof searchParams.filter_recent_viewed === "boolean"
|
|
741
743
|
? searchParams.filter_recent_viewed
|
|
742
|
-
: null
|
|
744
|
+
: null,
|
|
745
|
+
skip_recent_colleague_contacted: searchParams.skip_recent_colleague_contacted !== false
|
|
743
746
|
};
|
|
744
747
|
return Boolean(
|
|
745
748
|
job
|
|
@@ -751,6 +754,7 @@ export function hasRecruitSearchParams(searchParams = {}) {
|
|
|
751
754
|
|| age
|
|
752
755
|
|| normalized.keyword
|
|
753
756
|
|| typeof normalized.filter_recent_viewed === "boolean"
|
|
757
|
+
|| typeof normalized.skip_recent_colleague_contacted === "boolean"
|
|
754
758
|
);
|
|
755
759
|
}
|
|
756
760
|
|
|
@@ -2365,19 +2369,23 @@ export async function setRecruitAge(client, frameNodeId, age) {
|
|
|
2365
2369
|
};
|
|
2366
2370
|
}
|
|
2367
2371
|
|
|
2368
|
-
|
|
2372
|
+
async function setRecruitCheckboxFilter(client, frameNodeId, enabled, {
|
|
2373
|
+
selectors,
|
|
2374
|
+
label,
|
|
2375
|
+
errorLabel
|
|
2376
|
+
} = {}) {
|
|
2369
2377
|
if (typeof enabled !== "boolean") {
|
|
2370
2378
|
return { applied: false, reason: "not_requested" };
|
|
2371
2379
|
}
|
|
2372
2380
|
const { candidate, candidates } = await findTextCandidate(
|
|
2373
2381
|
client,
|
|
2374
2382
|
frameNodeId,
|
|
2375
|
-
|
|
2376
|
-
|
|
2383
|
+
selectors,
|
|
2384
|
+
label,
|
|
2377
2385
|
{ match: "contains" }
|
|
2378
2386
|
);
|
|
2379
2387
|
if (!candidate) {
|
|
2380
|
-
throw new Error("Recruit
|
|
2388
|
+
throw new Error(`${errorLabel || "Recruit checkbox filter"} was not found`);
|
|
2381
2389
|
}
|
|
2382
2390
|
|
|
2383
2391
|
let box = null;
|
|
@@ -2406,6 +2414,22 @@ export async function setRecruitRecentViewedFilter(client, frameNodeId, enabled)
|
|
|
2406
2414
|
};
|
|
2407
2415
|
}
|
|
2408
2416
|
|
|
2417
|
+
export async function setRecruitRecentViewedFilter(client, frameNodeId, enabled) {
|
|
2418
|
+
return setRecruitCheckboxFilter(client, frameNodeId, enabled, {
|
|
2419
|
+
selectors: RECRUIT_SEARCH_SELECTORS.recentViewedLabel,
|
|
2420
|
+
label: "过滤近14天查看",
|
|
2421
|
+
errorLabel: "Recruit recent-viewed filter"
|
|
2422
|
+
});
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
export async function setRecruitExchangeResumeFilter(client, frameNodeId, enabled) {
|
|
2426
|
+
return setRecruitCheckboxFilter(client, frameNodeId, enabled, {
|
|
2427
|
+
selectors: RECRUIT_SEARCH_SELECTORS.exchangeResumeLabel,
|
|
2428
|
+
label: "近30天未和同事交换简历",
|
|
2429
|
+
errorLabel: "Recruit exchange-resume filter"
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2409
2433
|
async function openRecruitCityPicker(client, frameNodeId, {
|
|
2410
2434
|
settleMs = 350
|
|
2411
2435
|
} = {}) {
|
|
@@ -3004,6 +3028,16 @@ export async function applyRecruitSearchParams(client, {
|
|
|
3004
3028
|
normalizedSearchParams.filter_recent_viewed
|
|
3005
3029
|
)
|
|
3006
3030
|
});
|
|
3031
|
+
} else if (stepName === "exchange_resume") {
|
|
3032
|
+
const exchangeFilterRoots = await getRecruitRoots(client);
|
|
3033
|
+
steps.push({
|
|
3034
|
+
step: "exchange_resume",
|
|
3035
|
+
result: await setRecruitExchangeResumeFilter(
|
|
3036
|
+
client,
|
|
3037
|
+
exchangeFilterRoots.iframe.documentNodeId,
|
|
3038
|
+
normalizedSearchParams.skip_recent_colleague_contacted
|
|
3039
|
+
)
|
|
3040
|
+
});
|
|
3007
3041
|
}
|
|
3008
3042
|
}
|
|
3009
3043
|
|
package/src/index.js
CHANGED
|
@@ -800,11 +800,13 @@ function createRunInputSchema() {
|
|
|
800
800
|
enum: ["不限", "男", "女"]
|
|
801
801
|
},
|
|
802
802
|
recent_not_view_confirmed: { type: "boolean" },
|
|
803
|
-
recent_not_view_value: {
|
|
804
|
-
type: "string",
|
|
805
|
-
enum: ["不限", "近14天没有"]
|
|
806
|
-
},
|
|
807
|
-
|
|
803
|
+
recent_not_view_value: {
|
|
804
|
+
type: "string",
|
|
805
|
+
enum: ["不限", "近14天没有"]
|
|
806
|
+
},
|
|
807
|
+
skip_recent_colleague_contacted_confirmed: { type: "boolean" },
|
|
808
|
+
skip_recent_colleague_contacted_value: { type: "boolean" },
|
|
809
|
+
criteria_confirmed: { type: "boolean" },
|
|
808
810
|
target_count_confirmed: { type: "boolean" },
|
|
809
811
|
target_count_value: {
|
|
810
812
|
type: "integer",
|
|
@@ -874,11 +876,15 @@ function createRunInputSchema() {
|
|
|
874
876
|
type: "string",
|
|
875
877
|
enum: ["不限", "男", "女"]
|
|
876
878
|
},
|
|
877
|
-
recent_not_view: {
|
|
878
|
-
type: "string",
|
|
879
|
-
enum: ["不限", "近14天没有"]
|
|
880
|
-
},
|
|
881
|
-
|
|
879
|
+
recent_not_view: {
|
|
880
|
+
type: "string",
|
|
881
|
+
enum: ["不限", "近14天没有"]
|
|
882
|
+
},
|
|
883
|
+
skip_recent_colleague_contacted: {
|
|
884
|
+
type: "boolean",
|
|
885
|
+
description: "默认 true。推荐页跳过近14天同事沟通过的人选;搜索页使用近30天未和同事交换简历过滤。"
|
|
886
|
+
},
|
|
887
|
+
criteria: { type: "string" },
|
|
882
888
|
job: { type: "string" },
|
|
883
889
|
target_count: { type: "integer", minimum: 1 },
|
|
884
890
|
max_greet_count: { type: "integer", minimum: 1 },
|
|
@@ -1382,7 +1388,9 @@ function createCompactRunInputSchema() {
|
|
|
1382
1388
|
final_confirmed: {
|
|
1383
1389
|
type: "boolean",
|
|
1384
1390
|
description: "用户完成总确认后传 true"
|
|
1385
|
-
}
|
|
1391
|
+
},
|
|
1392
|
+
skip_recent_colleague_contacted_confirmed: { type: "boolean" },
|
|
1393
|
+
skip_recent_colleague_contacted_value: { type: "boolean" }
|
|
1386
1394
|
},
|
|
1387
1395
|
additionalProperties: true
|
|
1388
1396
|
},
|
|
@@ -1404,6 +1412,7 @@ function createCompactRunInputSchema() {
|
|
|
1404
1412
|
},
|
|
1405
1413
|
gender: { type: "string" },
|
|
1406
1414
|
recent_not_view: { type: "string" },
|
|
1415
|
+
skip_recent_colleague_contacted: { type: "boolean" },
|
|
1407
1416
|
criteria: { type: "string" },
|
|
1408
1417
|
target_count: targetCountSchema,
|
|
1409
1418
|
post_action: { type: "string", enum: ["greet", "none"] },
|
package/src/parser.js
CHANGED
|
@@ -302,6 +302,16 @@ function normalizeRecentNotView(value) {
|
|
|
302
302
|
return RECENT_NOT_VIEW_OPTIONS.includes(normalized) ? normalized : null;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
+
function normalizeBooleanOverride(value) {
|
|
306
|
+
if (typeof value === "boolean") return value;
|
|
307
|
+
if (typeof value === "number") return value !== 0;
|
|
308
|
+
const normalized = normalizeText(value).toLowerCase();
|
|
309
|
+
if (!normalized) return null;
|
|
310
|
+
if (["true", "yes", "y", "1", "on", "enable", "enabled", "需要", "是", "开启"].includes(normalized)) return true;
|
|
311
|
+
if (["false", "no", "n", "0", "off", "disable", "disabled", "不需要", "否", "关闭"].includes(normalized)) return false;
|
|
312
|
+
return null;
|
|
313
|
+
}
|
|
314
|
+
|
|
305
315
|
function normalizePostAction(value) {
|
|
306
316
|
const normalized = normalizeText(value).toLowerCase();
|
|
307
317
|
if (!normalized) return null;
|
|
@@ -658,6 +668,16 @@ export function parseRecommendInstruction({ instruction, confirmation, overrides
|
|
|
658
668
|
|| ""
|
|
659
669
|
);
|
|
660
670
|
const pageScopeResolution = resolvePageScope({ instruction: text, confirmation, overrides, finalConfirmed });
|
|
671
|
+
const hasSkipRecentColleagueOverride = Object.prototype.hasOwnProperty.call(
|
|
672
|
+
overrides || {},
|
|
673
|
+
"skip_recent_colleague_contacted"
|
|
674
|
+
);
|
|
675
|
+
const confirmationSkipRecentColleagueContacted = normalizeBooleanOverride(
|
|
676
|
+
confirmation?.skip_recent_colleague_contacted_value
|
|
677
|
+
);
|
|
678
|
+
const skipRecentColleagueContacted = hasSkipRecentColleagueOverride
|
|
679
|
+
? normalizeBooleanOverride(overrides?.skip_recent_colleague_contacted) ?? true
|
|
680
|
+
: confirmationSkipRecentColleagueContacted ?? true;
|
|
661
681
|
|
|
662
682
|
const inferredSchoolTag = detectedSchoolTags.length > 0
|
|
663
683
|
? sortSchoolTagSelections(detectedSchoolTags)
|
|
@@ -680,7 +700,9 @@ export function parseRecommendInstruction({ instruction, confirmation, overrides
|
|
|
680
700
|
criteria: criteriaResolution.raw || criteriaResolution.normalized || null,
|
|
681
701
|
target_count: null,
|
|
682
702
|
post_action: null,
|
|
683
|
-
max_greet_count: null
|
|
703
|
+
max_greet_count: null,
|
|
704
|
+
skip_recent_colleague_contacted: skipRecentColleagueContacted,
|
|
705
|
+
colleague_contact_window_days: 14
|
|
684
706
|
};
|
|
685
707
|
const targetCountResolution = resolveTargetCount({ instruction: text, confirmation, overrides, finalConfirmed });
|
|
686
708
|
screenParams.target_count = targetCountResolution.target_count;
|
|
@@ -722,6 +744,12 @@ export function parseRecommendInstruction({ instruction, confirmation, overrides
|
|
|
722
744
|
const needs_post_action_confirmation = postActionResolution.needs_post_action_confirmation;
|
|
723
745
|
const needs_max_greet_count_confirmation = maxGreetCountResolution.needs_max_greet_count_confirmation;
|
|
724
746
|
const needs_page_confirmation = pageScopeResolution.needs_page_confirmation;
|
|
747
|
+
const needs_skip_recent_colleague_contacted_confirmation = (
|
|
748
|
+
!finalConfirmed
|
|
749
|
+
&& !hasSkipRecentColleagueOverride
|
|
750
|
+
&& confirmationSkipRecentColleagueContacted === null
|
|
751
|
+
&& confirmation?.skip_recent_colleague_contacted_confirmed !== true
|
|
752
|
+
);
|
|
725
753
|
const pending_questions = [];
|
|
726
754
|
|
|
727
755
|
if (needs_page_confirmation) {
|
|
@@ -829,6 +857,18 @@ export function parseRecommendInstruction({ instruction, confirmation, overrides
|
|
|
829
857
|
});
|
|
830
858
|
}
|
|
831
859
|
|
|
860
|
+
if (needs_skip_recent_colleague_contacted_confirmation) {
|
|
861
|
+
pending_questions.push({
|
|
862
|
+
field: "skip_recent_colleague_contacted",
|
|
863
|
+
question: "是否跳过最近已被同事联系过的人选?推荐页会检查近14天同事沟通记录。",
|
|
864
|
+
value: true,
|
|
865
|
+
options: [
|
|
866
|
+
{ label: "跳过(推荐)", value: true },
|
|
867
|
+
{ label: "不跳过", value: false }
|
|
868
|
+
]
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
|
|
832
872
|
return {
|
|
833
873
|
searchParams,
|
|
834
874
|
screenParams,
|
|
@@ -844,6 +884,7 @@ export function parseRecommendInstruction({ instruction, confirmation, overrides
|
|
|
844
884
|
needs_post_action_confirmation,
|
|
845
885
|
needs_max_greet_count_confirmation,
|
|
846
886
|
needs_page_confirmation,
|
|
887
|
+
needs_skip_recent_colleague_contacted_confirmation,
|
|
847
888
|
criteria_normalized: criteriaResolution.normalized,
|
|
848
889
|
proposed_target_count: targetCountResolution.proposed_target_count,
|
|
849
890
|
proposed_post_action: postActionResolution.proposed_post_action,
|
|
@@ -860,7 +901,9 @@ export function parseRecommendInstruction({ instruction, confirmation, overrides
|
|
|
860
901
|
criteria_normalized: criteriaResolution.normalized,
|
|
861
902
|
target_count: targetCountResolution.proposed_target_count,
|
|
862
903
|
post_action: postActionResolution.proposed_post_action,
|
|
863
|
-
max_greet_count: maxGreetCountResolution.proposed_max_greet_count
|
|
904
|
+
max_greet_count: maxGreetCountResolution.proposed_max_greet_count,
|
|
905
|
+
skip_recent_colleague_contacted: screenParams.skip_recent_colleague_contacted,
|
|
906
|
+
colleague_contact_window_days: screenParams.colleague_contact_window_days
|
|
864
907
|
},
|
|
865
908
|
current_page_scope: pageScopeResolution.page_scope,
|
|
866
909
|
current_search_params: searchParams,
|
package/src/recommend-mcp.js
CHANGED
|
@@ -1384,6 +1384,7 @@ function buildRequiredConfirmations(parsed, args = {}) {
|
|
|
1384
1384
|
if (parsed.needs_criteria_confirmation) required.push("criteria");
|
|
1385
1385
|
if (parsed.needs_target_count_confirmation) required.push("target_count");
|
|
1386
1386
|
if (parsed.needs_post_action_confirmation) required.push("post_action");
|
|
1387
|
+
if (parsed.needs_skip_recent_colleague_contacted_confirmation) required.push("skip_recent_colleague_contacted");
|
|
1387
1388
|
if ((parsed.suspicious_fields || []).length) required.push("suspicious_fields");
|
|
1388
1389
|
|
|
1389
1390
|
const confirmation = args.confirmation || {};
|
|
@@ -1591,14 +1592,16 @@ function normalizeRecommendStartInput(args = {}, parsed, configResolution = null
|
|
|
1591
1592
|
targetCount,
|
|
1592
1593
|
job: normalizeText(confirmation.job_value || overrides.job || ""),
|
|
1593
1594
|
pageScope: parsed.page_scope || "recommend",
|
|
1594
|
-
filter: buildRecommendFilter(parsed, args),
|
|
1595
|
-
postAction: parsed.screenParams?.post_action || "none",
|
|
1596
|
-
maxGreetCount: Number.isInteger(parsed.screenParams?.max_greet_count)
|
|
1597
|
-
? parsed.screenParams.max_greet_count
|
|
1598
|
-
: null,
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1595
|
+
filter: buildRecommendFilter(parsed, args),
|
|
1596
|
+
postAction: parsed.screenParams?.post_action || "none",
|
|
1597
|
+
maxGreetCount: Number.isInteger(parsed.screenParams?.max_greet_count)
|
|
1598
|
+
? parsed.screenParams.max_greet_count
|
|
1599
|
+
: null,
|
|
1600
|
+
skipRecentColleagueContacted: parsed.screenParams?.skip_recent_colleague_contacted !== false,
|
|
1601
|
+
colleagueContactWindowDays: 14,
|
|
1602
|
+
screeningMode: normalizeScreeningModeArg(args)
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1602
1605
|
|
|
1603
1606
|
function getRunOptions(args, parsed, normalized, session, configResolution = null) {
|
|
1604
1607
|
const slowLive = args.slow_live === true;
|
|
@@ -1636,8 +1639,8 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
|
|
|
1636
1639
|
executePostAction,
|
|
1637
1640
|
actionTimeoutMs: parsePositiveInteger(args.action_timeout_ms, slowLive ? 12000 : 8000),
|
|
1638
1641
|
actionIntervalMs: parsePositiveInteger(args.action_interval_ms, 500),
|
|
1639
|
-
actionAfterClickDelayMs: parseNonNegativeInteger(args.action_after_click_delay_ms, slowLive ? 1200 : 900),
|
|
1640
|
-
screeningMode: normalized.screeningMode,
|
|
1642
|
+
actionAfterClickDelayMs: parseNonNegativeInteger(args.action_after_click_delay_ms, slowLive ? 1200 : 900),
|
|
1643
|
+
screeningMode: normalized.screeningMode,
|
|
1641
1644
|
llmConfig: normalized.screeningMode === "llm" && configResolution?.ok ? {
|
|
1642
1645
|
...configResolution.config
|
|
1643
1646
|
} : null,
|
|
@@ -1655,6 +1658,8 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
|
|
|
1655
1658
|
imageOutputDir: resolveBossConfiguredOutputDir("", getRunsDir()),
|
|
1656
1659
|
humanRestEnabled: humanBehavior.restEnabled,
|
|
1657
1660
|
humanBehavior,
|
|
1661
|
+
skipRecentColleagueContacted: normalized.skipRecentColleagueContacted,
|
|
1662
|
+
colleagueContactWindowDays: normalized.colleagueContactWindowDays,
|
|
1658
1663
|
name: "mcp-recommend-pipeline-run",
|
|
1659
1664
|
parsed
|
|
1660
1665
|
};
|
package/src/recruit-mcp.js
CHANGED
|
@@ -710,6 +710,8 @@ export function createRecruitPipelineInputSchema() {
|
|
|
710
710
|
search_params_confirmed: { type: "boolean" },
|
|
711
711
|
criteria_confirmed: { type: "boolean" },
|
|
712
712
|
criteria_value: { type: "string" },
|
|
713
|
+
skip_recent_colleague_contacted_confirmed: { type: "boolean" },
|
|
714
|
+
skip_recent_colleague_contacted_value: { type: "boolean" },
|
|
713
715
|
post_action_confirmed: { type: "boolean" },
|
|
714
716
|
post_action_value: {
|
|
715
717
|
type: "string",
|
|
@@ -740,6 +742,10 @@ export function createRecruitPipelineInputSchema() {
|
|
|
740
742
|
]
|
|
741
743
|
},
|
|
742
744
|
filter_recent_viewed: { type: "boolean" },
|
|
745
|
+
skip_recent_colleague_contacted: {
|
|
746
|
+
type: "boolean",
|
|
747
|
+
description: "默认 true。搜索页使用 Boss 的“近30天未和同事交换简历”过滤;false 会确保该过滤取消。"
|
|
748
|
+
},
|
|
743
749
|
recent_not_view: {
|
|
744
750
|
anyOf: [
|
|
745
751
|
{ type: "boolean" },
|
|
@@ -1043,6 +1049,7 @@ function buildRequiredConfirmations(parsedResult) {
|
|
|
1043
1049
|
if (parsedResult.needs_search_params_confirmation) confirmations.push("search_params");
|
|
1044
1050
|
if (parsedResult.needs_keyword_confirmation) confirmations.push("keyword");
|
|
1045
1051
|
if (parsedResult.needs_recent_viewed_filter_confirmation) confirmations.push("filter_recent_viewed");
|
|
1052
|
+
if (parsedResult.needs_skip_recent_colleague_contacted_confirmation) confirmations.push("skip_recent_colleague_contacted");
|
|
1046
1053
|
if (parsedResult.needs_criteria_confirmation) confirmations.push("criteria");
|
|
1047
1054
|
if (parsedResult.has_unresolved_missing_fields) confirmations.push("missing_fields_or_defaults");
|
|
1048
1055
|
if ((parsedResult.suspicious_fields || []).length) confirmations.push("suspicious_fields");
|
|
@@ -1110,6 +1117,7 @@ function evaluateRecruitPipelineGate(parsed) {
|
|
|
1110
1117
|
if (
|
|
1111
1118
|
parsed.needs_keyword_confirmation
|
|
1112
1119
|
|| parsed.needs_recent_viewed_filter_confirmation
|
|
1120
|
+
|| parsed.needs_skip_recent_colleague_contacted_confirmation
|
|
1113
1121
|
|| parsed.needs_criteria_confirmation
|
|
1114
1122
|
|| parsed.needs_search_params_confirmation
|
|
1115
1123
|
|| (parsed.suspicious_fields || []).length > 0
|