@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.
@@ -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
- export async function setRecruitRecentViewedFilter(client, frameNodeId, enabled) {
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
- RECRUIT_SEARCH_SELECTORS.recentViewedLabel,
2376
- "过滤近14天查看",
2383
+ selectors,
2384
+ label,
2377
2385
  { match: "contains" }
2378
2386
  );
2379
2387
  if (!candidate) {
2380
- throw new Error("Recruit recent-viewed filter was not found");
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
- criteria_confirmed: { type: "boolean" },
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
- criteria: { type: "string" },
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,
@@ -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
- screeningMode: normalizeScreeningModeArg(args)
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
  };
@@ -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