@reconcrap/boss-recommend-mcp 2.1.10 → 2.1.11

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 CHANGED
@@ -100,6 +100,7 @@ MCP 工具:
100
100
  - `resume_recruit_pipeline_run`
101
101
  - `cancel_recruit_pipeline_run`
102
102
  - `boss_chat_health_check`
103
+ - `list_boss_chat_jobs`(只读读取聊天页岗位列表;chat-only 获取 `job_options` 的首选别名,不会启动任务)
103
104
  - `prepare_boss_chat_run`
104
105
  - `start_boss_chat_run`
105
106
  - `get_boss_chat_run`
@@ -424,7 +425,7 @@ node src/cli.js chat prepare-run --slow-live --port 9222
424
425
  - `baseUrl` / `apiKey` / `model` 不再单独传入,固定复用 recommend 的 `screening-config.json`
425
426
  - `greeting_text` 默认优先级:本次显式值 > `screening-config.json.greetingMessage` > 内置默认招呼语(`Hi同学,能麻烦发下简历吗?`)
426
427
  - 若缺少 `follow_up.chat` 必填项,pipeline 会返回 `NEED_INPUT`
427
- - 如需聊天页筛选,请调用 `prepare_boss_chat_run` 获取岗位列表,再调用 `start_boss_chat_run`。
428
+ - 如需聊天页筛选,请调用 `list_boss_chat_jobs` 或 `prepare_boss_chat_run` 获取岗位列表,再调用 `start_boss_chat_run`。chat-only、未读、全部聊天、求简历任务不要调用 `list_recommend_jobs` / `run_recommend` / `start_recommend_pipeline_run`;这些 recommend 工具会对明确的 chat/search 误路由 fail closed。
428
429
  - `boss-chat` 状态统一写入 `~/.boss-recommend-mcp/boss-chat`(或 `BOSS_CHAT_HOME` 指定目录),不再依赖工作区 `cwd`
429
430
 
430
431
  ## Chat-only
@@ -438,6 +439,7 @@ node src/cli.js chat prepare-run --slow-live --port 9222
438
439
  - `boss-recommend-mcp chat get-run|pause-run|resume-run|cancel-run`
439
440
  - MCP:
440
441
  - `boss_chat_health_check`
442
+ - `list_boss_chat_jobs`
441
443
  - `prepare_boss_chat_run`
442
444
  - `start_boss_chat_run`
443
445
  - `get_boss_chat_run`
@@ -450,14 +452,15 @@ node src/cli.js chat prepare-run --slow-live --port 9222
450
452
 
451
453
  chat-only 交互建议:
452
454
 
453
- - 先调用一次 `prepare_boss_chat_run`(可不带参数),服务会先导航到 `https://www.zhipin.com/web/chat/index` 并返回 `NEED_INPUT`,其中包含岗位 `job_options` 与待补字段。
455
+ - 先调用一次 `list_boss_chat_jobs` 或 `prepare_boss_chat_run`(可不带参数),服务会先导航到 `https://www.zhipin.com/web/chat/index` 并返回 `NEED_INPUT`,其中包含岗位 `job_options` 与待补字段。
454
456
  - 然后基于 `job_options` 让用户选择 `job`,并补齐 `start_from`、`target_count`、`criteria` 后调用 `start_boss_chat_run` 启动任务。
455
457
  - `greeting_text` 可选;未传时使用 `screening-config.json.greetingMessage`,若未配置则使用默认招呼语(`Hi同学,能麻烦发下简历吗?`)。
456
458
  - `target_count` 支持正整数、`all`、`-1`;若用户给出 `全部候选人` / `所有候选人`,会自动按不限(扫到底)处理。
457
459
 
458
460
  Trae-CN / 长对话防循环建议:
459
461
 
460
- - 固定流程:`boss_chat_health_check` -> `prepare_boss_chat_run(空参可)` -> 一次性补齐 `job/start_from/target_count/criteria` -> `start_boss_chat_run`。
462
+ - 固定流程:`boss_chat_health_check` -> `list_boss_chat_jobs(空参可)` / `prepare_boss_chat_run(空参可)` -> 一次性补齐 `job/start_from/target_count/criteria` -> `start_boss_chat_run`。
463
+ - chat-only 场景严禁调用 `list_recommend_jobs`、`run_recommend` 或 `start_recommend_pipeline_run`。
461
464
  - `start_boss_chat_run` 的工具 schema 已把 `job/start_from/target_count/criteria` 标记为必填;不要用它获取岗位列表。
462
465
  - 若 `pending_questions` / UI 选项里出现“扫到底(必须传 `target_count="all"`)”,下一次工具调用请直接照抄 `"target_count": "all"`,不要只保留“扫到底”这层自然语言语义。
463
466
  - `start_boss_chat_run` 返回 `ACCEPTED` 后直接结束当前回合,不要自动轮询。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reconcrap/boss-recommend-mcp",
3
- "version": "2.1.10",
3
+ "version": "2.1.11",
4
4
  "description": "Unified MCP pipeline for recommend-page filtering and screening on Boss Zhipin",
5
5
  "keywords": [
6
6
  "boss",
@@ -16,7 +16,7 @@ Please run a Boss chat-only task (do not switch to recommend flow).
16
16
 
17
17
  Execution order:
18
18
  1) Call boss_chat_health_check.
19
- 2) Call prepare_boss_chat_run once (empty params allowed) to fetch job_options and missing fields.
19
+ 2) Call list_boss_chat_jobs once (empty params allowed), or prepare_boss_chat_run once, to fetch job_options and missing fields.
20
20
  3) Ask for these required fields in one shot: job, start_from (unread/all), target_count, criteria, rest_level (low/medium/high).
21
21
  4) After user reply, call start_boss_chat_run exactly once to start the run.
22
22
  5) If ACCEPTED, reply only with run_id and "task started"; no auto polling.
@@ -24,6 +24,8 @@ Execution order:
24
24
  Anti-loop rules:
25
25
  - Do not repeat the same sentence across turns.
26
26
  - On validation errors, list all missing/invalid fields once.
27
+ - Do not call list_recommend_jobs for chat-only tasks; it is recommend-page only and will switch the browser to /web/chat/recommend.
28
+ - Do not call run_recommend or start_recommend_pipeline_run for chat-only tasks; use start_boss_chat_run.
27
29
  - Do not use start_boss_chat_run for preflight. It is only for the final start call and must include job/start_from/target_count/criteria.
28
30
  - Do not call start_boss_chat_run repeatedly in one turn.
29
31
  - Do not call get_boss_chat_run unless user explicitly asks for progress.
@@ -14,6 +14,7 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
14
14
  ## Tool Routing
15
15
 
16
16
  - 健康检查:`boss_chat_health_check`
17
+ - 只读获取聊天页岗位列表:`list_boss_chat_jobs`
17
18
  - 预备并获取岗位列表:`prepare_boss_chat_run`
18
19
  - 启动异步任务:`start_boss_chat_run`
19
20
  - 查询进度:`get_boss_chat_run`
@@ -69,6 +70,8 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
69
70
  - 若本机找不到 Chrome,可提示用户设置 `BOSS_MCP_CHROME_PATH` 或 `BOSS_RECOMMEND_CHROME_PATH`;非本机 debug host 不自动启动。
70
71
  - `job` / `start_from` / `criteria` 缺一不可;缺参时只补缺口。
71
72
  - `target_count` 在 chat-only 启动前也是必填项,不能默认省略。
73
+ - chat-only 岗位列表只能通过 `list_boss_chat_jobs` 或 `prepare_boss_chat_run` 获取;严禁调用 `list_recommend_jobs`,因为它会切到推荐页。
74
+ - chat-only 启动只能调用 `start_boss_chat_run`;严禁调用 `run_recommend` 或 `start_recommend_pipeline_run`。
72
75
  - 每次 run 必须明确询问用户本次休息强度 `rest_level`:`low`(旧策略)/ `medium`(约 5 小时或 700 人累计休息 30 分钟)/ `high`(约 5 小时或 700 人累计休息 1 小时);不得默认使用配置文件里的值替用户决定。
73
76
  - 当用户说“全部候选人/所有候选人”时,必须按“扫到底(unlimited)”处理,不要再追问正整数。
74
77
  - 参数名必须写 `target_count`(不要写“目标数量”等中文键名)。
@@ -77,7 +80,7 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
77
80
  - 若工具或提问选项里出现“扫到底(必须传 `target_count=\"all\"`)”之类字样,下一次工具调用时必须直接照抄这个字面量,不要只保留“扫到底”语义。
78
81
  - 禁止 agent 自行补全 `job/start_from/criteria` 并直接执行,必须由用户明确给出或确认。
79
82
  - chat-only 启动流程必须先进入聊天页并拉取岗位列表,再让用户从列表中选择 `job`。
80
- - 必须先用空参调用 `prepare_boss_chat_run` 获取 `job_options`;不要用 `start_boss_chat_run` 做预备调用。
83
+ - 必须先用空参调用 `list_boss_chat_jobs` 或 `prepare_boss_chat_run` 获取 `job_options`;不要用 `start_boss_chat_run` 做预备调用。
81
84
  - `start_boss_chat_run` 只能用于真正启动,必须一次性传齐 `job` / `start_from` / `target_count` / `criteria`。
82
85
  - 若 `start_boss_chat_run` 返回 `NEED_INPUT` 且 `missing_fields` 包含 `target_count`,说明你没有把用户选择写入工具参数;下一次调用必须照 `next_call_example` 原样补上 `"target_count": "all"` 或正整数,不要重复空调用。
83
86
  - 默认不自动轮询;只有用户要求查进度时才调用 `get_boss_chat_run`。
@@ -96,6 +99,6 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
96
99
  ## Response Style
97
100
 
98
101
  - 用结构化中文。
99
- - 首轮建议先调用一次 `prepare_boss_chat_run`(可空参)获取 `job_options` 与 `pending_questions`。
102
+ - 首轮建议先调用一次 `list_boss_chat_jobs`(可空参)或 `prepare_boss_chat_run`(可空参)获取 `job_options` 与 `pending_questions`。
100
103
  - 缺参时必须逐项确认:`job`(来自岗位列表)、`start_from`(`unread|all`)、`target_count`、`criteria`、`rest_level`。
101
104
  - 若健康检查失败,明确提示共享配置文件 `screening-config.json` 不可用。
package/src/index.js CHANGED
@@ -110,6 +110,7 @@ const TOOL_RUN_FEATURED_CALIBRATION = "run_featured_calibration";
110
110
  const TOOL_GET_FEATURED_CALIBRATION_STATUS = "get_featured_calibration_status";
111
111
  const TOOL_RUN_RECOMMEND_SELF_HEAL = "run_recommend_self_heal";
112
112
  const TOOL_BOSS_CHAT_HEALTH_CHECK = "boss_chat_health_check";
113
+ const TOOL_BOSS_CHAT_LIST_JOBS = "list_boss_chat_jobs";
113
114
  const TOOL_BOSS_CHAT_PREPARE_RUN = "prepare_boss_chat_run";
114
115
  const TOOL_BOSS_CHAT_START_RUN = "start_boss_chat_run";
115
116
  const TOOL_BOSS_CHAT_GET_RUN = "get_boss_chat_run";
@@ -1295,9 +1296,107 @@ function createScheduleRunInputSchema() {
1295
1296
 
1296
1297
  function createToolsSchema() {
1297
1298
  return [
1299
+ {
1300
+ name: TOOL_BOSS_CHAT_HEALTH_CHECK,
1301
+ description: "Boss 聊天页/chat-only 健康检查。chat-only、未读、全部聊天、求简历等任务必须先走 boss-chat 工具,不要调用 list_recommend_jobs 或 start_recommend_pipeline_run。",
1302
+ inputSchema: {
1303
+ type: "object",
1304
+ properties: {
1305
+ host: {
1306
+ type: "string",
1307
+ description: "可选,Chrome 调试 host;默认 127.0.0.1"
1308
+ },
1309
+ port: {
1310
+ type: "integer",
1311
+ minimum: 1,
1312
+ description: "可选,Chrome 调试端口;默认读取 screening-config.json.debugPort 或 9222"
1313
+ },
1314
+ target_url_includes: {
1315
+ type: "string",
1316
+ description: "可选,Chrome target URL 匹配片段;默认 Boss chat 页"
1317
+ },
1318
+ allow_navigate: {
1319
+ type: "boolean",
1320
+ description: "可选,未在 chat 页时允许通过 Page.navigate 切换;默认 true"
1321
+ },
1322
+ slow_live: {
1323
+ type: "boolean",
1324
+ description: "可选,VPN/慢页面 live 测试模式,放宽等待时间"
1325
+ }
1326
+ },
1327
+ additionalProperties: false
1328
+ }
1329
+ },
1330
+ {
1331
+ name: TOOL_BOSS_CHAT_LIST_JOBS,
1332
+ description: "只读读取 Boss 聊天页岗位列表;这是 chat-only 获取 job_options 的首选别名,等价于 prepare_boss_chat_run 的预备步骤但不会启动任务。聊天页/未读/全部聊天/求简历任务必须用本工具或 prepare_boss_chat_run,严禁用 list_recommend_jobs。",
1333
+ inputSchema: createBossChatStartInputSchema()
1334
+ },
1335
+ {
1336
+ name: TOOL_BOSS_CHAT_PREPARE_RUN,
1337
+ description: "预备一次 boss-chat/chat-only 任务:只导航聊天页并返回岗位列表与待补字段,不会启动任务。用它先获取 job_options;不要用 list_recommend_jobs。",
1338
+ inputSchema: createBossChatStartInputSchema()
1339
+ },
1340
+ {
1341
+ name: TOOL_BOSS_CHAT_START_RUN,
1342
+ description: "异步启动一次 boss-chat/chat-only 任务。必须一次性提供 job、start_from、target_count、criteria;若用户选择扫到底/不限/全部候选人,必须字面传 target_count=\"all\"。严禁改用 start_recommend_pipeline_run。",
1343
+ inputSchema: createBossChatStartInputSchema({ requireFullInput: true })
1344
+ },
1345
+ {
1346
+ name: TOOL_BOSS_CHAT_GET_RUN,
1347
+ description: "查询 boss-chat run_id 的当前状态。chat-only 状态查询用本工具,不要用 get_recommend_pipeline_run。",
1348
+ inputSchema: {
1349
+ type: "object",
1350
+ properties: {
1351
+ run_id: { type: "string" },
1352
+ profile: { type: "string" }
1353
+ },
1354
+ required: ["run_id"],
1355
+ additionalProperties: false
1356
+ }
1357
+ },
1358
+ {
1359
+ name: TOOL_BOSS_CHAT_PAUSE_RUN,
1360
+ description: "暂停运行中的 boss-chat 任务。",
1361
+ inputSchema: {
1362
+ type: "object",
1363
+ properties: {
1364
+ run_id: { type: "string" },
1365
+ profile: { type: "string" }
1366
+ },
1367
+ required: ["run_id"],
1368
+ additionalProperties: false
1369
+ }
1370
+ },
1371
+ {
1372
+ name: TOOL_BOSS_CHAT_RESUME_RUN,
1373
+ description: "继续已暂停的 boss-chat 任务。",
1374
+ inputSchema: {
1375
+ type: "object",
1376
+ properties: {
1377
+ run_id: { type: "string" },
1378
+ profile: { type: "string" }
1379
+ },
1380
+ required: ["run_id"],
1381
+ additionalProperties: false
1382
+ }
1383
+ },
1384
+ {
1385
+ name: TOOL_BOSS_CHAT_CANCEL_RUN,
1386
+ description: "取消运行中的 boss-chat 任务。",
1387
+ inputSchema: {
1388
+ type: "object",
1389
+ properties: {
1390
+ run_id: { type: "string" },
1391
+ profile: { type: "string" }
1392
+ },
1393
+ required: ["run_id"],
1394
+ additionalProperties: false
1395
+ }
1396
+ },
1298
1397
  {
1299
1398
  name: TOOL_LIST_RECOMMEND_JOBS,
1300
- description: "CDP-only 读取 Boss 推荐页岗位下拉框,返回所有可用岗位完整名称,方便 cron/一次性任务提前填写 job 参数。不会启动筛选任务。",
1399
+ description: "CDP-only 读取 Boss 推荐页岗位下拉框,返回所有可用岗位完整名称,方便 recommend/推荐页 cron/一次性任务提前填写 job 参数。不会启动筛选任务。chat-only、未读、全部聊天、求简历任务严禁调用本工具,必须用 list_boss_chat_jobs 或 prepare_boss_chat_run。",
1301
1400
  inputSchema: createListRecommendJobsInputSchema()
1302
1401
  },
1303
1402
  {
@@ -1428,99 +1527,6 @@ function createToolsSchema() {
1428
1527
  description: "手动运维自愈工具:扫描 Boss recommend 相关 selector / network 规则漂移,并在确认后应用高置信度修复。",
1429
1528
  inputSchema: createRunRecommendSelfHealInputSchema()
1430
1529
  },
1431
- {
1432
- name: TOOL_BOSS_CHAT_HEALTH_CHECK,
1433
- description: "CDP-only 检查 Boss chat 页面、自愈 probes、共享 screening-config.json 与 chat runtime 目录是否可用。",
1434
- inputSchema: {
1435
- type: "object",
1436
- properties: {
1437
- host: {
1438
- type: "string",
1439
- description: "可选,Chrome 调试 host;默认 127.0.0.1"
1440
- },
1441
- port: {
1442
- type: "integer",
1443
- minimum: 1,
1444
- description: "可选,Chrome 调试端口;默认读取 screening-config.json.debugPort 或 9222"
1445
- },
1446
- target_url_includes: {
1447
- type: "string",
1448
- description: "可选,Chrome target URL 匹配片段;默认 Boss chat 页"
1449
- },
1450
- allow_navigate: {
1451
- type: "boolean",
1452
- description: "可选,未在 chat 页时允许通过 Page.navigate 切换;默认 true"
1453
- },
1454
- slow_live: {
1455
- type: "boolean",
1456
- description: "可选,VPN/慢页面 live 测试模式,放宽等待时间"
1457
- }
1458
- },
1459
- additionalProperties: false
1460
- }
1461
- },
1462
- {
1463
- name: TOOL_BOSS_CHAT_PREPARE_RUN,
1464
- description: "预备一次 boss-chat 任务:只导航聊天页并返回岗位列表与待补字段,不会启动任务。用它先获取 job_options。",
1465
- inputSchema: createBossChatStartInputSchema()
1466
- },
1467
- {
1468
- name: TOOL_BOSS_CHAT_START_RUN,
1469
- description: "异步启动一次 boss-chat 任务。必须一次性提供 job、start_from、target_count、criteria;若用户选择扫到底/不限/全部候选人,必须字面传 target_count=\"all\"。",
1470
- inputSchema: createBossChatStartInputSchema({ requireFullInput: true })
1471
- },
1472
- {
1473
- name: TOOL_BOSS_CHAT_GET_RUN,
1474
- description: "查询 boss-chat run_id 的当前状态。",
1475
- inputSchema: {
1476
- type: "object",
1477
- properties: {
1478
- run_id: { type: "string" },
1479
- profile: { type: "string" }
1480
- },
1481
- required: ["run_id"],
1482
- additionalProperties: false
1483
- }
1484
- },
1485
- {
1486
- name: TOOL_BOSS_CHAT_PAUSE_RUN,
1487
- description: "暂停运行中的 boss-chat 任务。",
1488
- inputSchema: {
1489
- type: "object",
1490
- properties: {
1491
- run_id: { type: "string" },
1492
- profile: { type: "string" }
1493
- },
1494
- required: ["run_id"],
1495
- additionalProperties: false
1496
- }
1497
- },
1498
- {
1499
- name: TOOL_BOSS_CHAT_RESUME_RUN,
1500
- description: "继续已暂停的 boss-chat 任务。",
1501
- inputSchema: {
1502
- type: "object",
1503
- properties: {
1504
- run_id: { type: "string" },
1505
- profile: { type: "string" }
1506
- },
1507
- required: ["run_id"],
1508
- additionalProperties: false
1509
- }
1510
- },
1511
- {
1512
- name: TOOL_BOSS_CHAT_CANCEL_RUN,
1513
- description: "取消运行中的 boss-chat 任务。",
1514
- inputSchema: {
1515
- type: "object",
1516
- properties: {
1517
- run_id: { type: "string" },
1518
- profile: { type: "string" }
1519
- },
1520
- required: ["run_id"],
1521
- additionalProperties: false
1522
- }
1523
- },
1524
1530
  {
1525
1531
  name: TOOL_RUN_RECRUIT_PIPELINE,
1526
1532
  description: "兼容 Boss recruit 入口:默认 async;sync 模式会等待终态。所有浏览器动作走共享 CDP-only recruit service。",
@@ -2885,7 +2891,7 @@ async function handleRequest(message, workspaceRoot) {
2885
2891
  }
2886
2892
  }
2887
2893
 
2888
- if ([TOOL_BOSS_CHAT_PREPARE_RUN, TOOL_BOSS_CHAT_START_RUN].includes(toolName)) {
2894
+ if ([TOOL_BOSS_CHAT_LIST_JOBS, TOOL_BOSS_CHAT_PREPARE_RUN, TOOL_BOSS_CHAT_START_RUN].includes(toolName)) {
2889
2895
  const inputError = validateBossChatStartArgs(args);
2890
2896
  if (inputError) {
2891
2897
  return createJsonRpcError(id, -32602, inputError);
@@ -2941,6 +2947,8 @@ async function handleRequest(message, workspaceRoot) {
2941
2947
  payload = await handleRunRecommendSelfHealTool({ workspaceRoot, args });
2942
2948
  } else if (toolName === TOOL_BOSS_CHAT_HEALTH_CHECK) {
2943
2949
  payload = await handleBossChatHealthCheckTool(workspaceRoot, args);
2950
+ } else if (toolName === TOOL_BOSS_CHAT_LIST_JOBS) {
2951
+ payload = await handleBossChatPrepareRunTool({ workspaceRoot, args });
2944
2952
  } else if (toolName === TOOL_BOSS_CHAT_PREPARE_RUN) {
2945
2953
  payload = await handleBossChatPrepareRunTool({ workspaceRoot, args });
2946
2954
  } else if (toolName === TOOL_BOSS_CHAT_START_RUN) {
@@ -75,13 +75,119 @@ let recommendRunService = createRecommendRunService({
75
75
  });
76
76
  const recommendRunMeta = new Map();
77
77
 
78
- function normalizeText(value) {
79
- return String(value || "").replace(/\s+/g, " ").trim();
80
- }
81
-
82
- function parsePositiveInteger(raw, fallback) {
83
- const parsed = Number.parseInt(String(raw || ""), 10);
84
- return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
78
+ function normalizeText(value) {
79
+ return String(value || "").replace(/\s+/g, " ").trim();
80
+ }
81
+
82
+ function collectRecommendRouteText(args = {}) {
83
+ return normalizeText([
84
+ args.instruction,
85
+ args.criteria,
86
+ args.target_url_includes,
87
+ args.page_scope,
88
+ args.confirmation?.page_value,
89
+ args.confirmation?.job_value,
90
+ args.overrides?.criteria,
91
+ args.overrides?.page_scope,
92
+ args.overrides?.job,
93
+ args.overrides?.target_url_includes
94
+ ].filter((value) => value !== undefined && value !== null).join(" "));
95
+ }
96
+
97
+ function findRouteSignals(text, patterns = []) {
98
+ const signals = [];
99
+ for (const { label, pattern } of patterns) {
100
+ if (pattern.test(text)) signals.push(label);
101
+ }
102
+ return signals;
103
+ }
104
+
105
+ function detectNonRecommendRoute(args = {}) {
106
+ const text = collectRecommendRouteText(args);
107
+ if (!text) return null;
108
+ const chatSignals = findRouteSignals(text, [
109
+ { label: "chat-only", pattern: /\bchat[-\s]?only\b/i },
110
+ { label: "boss-chat", pattern: /\bboss[-\s]?chat\b/i },
111
+ { label: "chat page", pattern: /\bchat\s+page\b/i },
112
+ { label: "chat/index", pattern: /(?:\/web\/chat\/index|chat\/index)/i },
113
+ { label: "聊天页", pattern: /聊天页/ },
114
+ { label: "聊天列表", pattern: /聊天列表/ },
115
+ { label: "未读", pattern: /未读/ },
116
+ { label: "全部聊天", pattern: /全部聊天|所有聊天/ },
117
+ { label: "求简历", pattern: /求简历|索要简历|要简历|在线简历/ }
118
+ ]);
119
+ if (chatSignals.length) {
120
+ return {
121
+ domain: "chat",
122
+ signals: chatSignals,
123
+ text
124
+ };
125
+ }
126
+ const searchSignals = findRouteSignals(text, [
127
+ { label: "search-only", pattern: /\bsearch[-\s]?only\b/i },
128
+ { label: "search page", pattern: /\bsearch\s+page\b/i },
129
+ { label: "recruit pipeline", pattern: /\brecruit\s+pipeline\b/i },
130
+ { label: "chat/search", pattern: /(?:\/web\/chat\/search|chat\/search)/i },
131
+ { label: "搜索页", pattern: /搜索页/ },
132
+ { label: "招聘搜索", pattern: /招聘搜索/ }
133
+ ]);
134
+ if (searchSignals.length) {
135
+ return {
136
+ domain: "search",
137
+ signals: searchSignals,
138
+ text
139
+ };
140
+ }
141
+ return null;
142
+ }
143
+
144
+ function buildWrongRecommendRouteResponse(route) {
145
+ if (route?.domain === "chat") {
146
+ return {
147
+ status: "FAILED",
148
+ route_guard: true,
149
+ error: {
150
+ code: "WRONG_BOSS_TOOL_FOR_CHAT",
151
+ message: "This request is explicitly chat-only/chat-page work. Do not use recommend tools. Use boss_chat_health_check, then list_boss_chat_jobs or prepare_boss_chat_run, then start_boss_chat_run.",
152
+ retryable: false
153
+ },
154
+ detected_domain: "chat",
155
+ detected_signals: route.signals || [],
156
+ recommended_tool_sequence: [
157
+ "boss_chat_health_check",
158
+ "list_boss_chat_jobs",
159
+ "prepare_boss_chat_run",
160
+ "start_boss_chat_run"
161
+ ]
162
+ };
163
+ }
164
+ if (route?.domain === "search") {
165
+ return {
166
+ status: "FAILED",
167
+ route_guard: true,
168
+ error: {
169
+ code: "WRONG_BOSS_TOOL_FOR_SEARCH",
170
+ message: "This request is explicitly search/recruit-page work. Do not use recommend tools. Use run_recruit_pipeline or start_recruit_pipeline_run.",
171
+ retryable: false
172
+ },
173
+ detected_domain: "search",
174
+ detected_signals: route.signals || [],
175
+ recommended_tool_sequence: [
176
+ "run_recruit_pipeline",
177
+ "start_recruit_pipeline_run"
178
+ ]
179
+ };
180
+ }
181
+ return null;
182
+ }
183
+
184
+ function guardRecommendRoute(args = {}) {
185
+ return buildWrongRecommendRouteResponse(detectNonRecommendRoute(args));
186
+ }
187
+
188
+ function parsePositiveInteger(raw, fallback) {
189
+ const parsed = Number.parseInt(String(raw || ""), 10);
190
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
85
191
  }
86
192
 
87
193
  function parseNonNegativeInteger(raw, fallback) {
@@ -855,9 +961,17 @@ async function readRecommendJobOptionsFromSession(session) {
855
961
  };
856
962
  }
857
963
 
858
- export async function listRecommendJobsTool({ workspaceRoot = "", args = {} } = {}) {
859
- const configResolution = resolveBossScreeningConfig(workspaceRoot);
860
- const host = normalizeText(args.host) || DEFAULT_RECOMMEND_HOST;
964
+ export async function listRecommendJobsTool({ workspaceRoot = "", args = {} } = {}) {
965
+ const routeGuard = guardRecommendRoute(args);
966
+ if (routeGuard) {
967
+ return {
968
+ ...routeGuard,
969
+ stage: "recommend_job_list",
970
+ message: "list_recommend_jobs is recommend-page only. For chat-only job lists, call list_boss_chat_jobs or prepare_boss_chat_run."
971
+ };
972
+ }
973
+ const configResolution = resolveBossScreeningConfig(workspaceRoot);
974
+ const host = normalizeText(args.host) || DEFAULT_RECOMMEND_HOST;
861
975
  const port = parsePositiveInteger(
862
976
  args.port,
863
977
  configResolution.ok ? configResolution.config.debugPort : DEFAULT_RECOMMEND_PORT
@@ -1477,8 +1591,10 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
1477
1591
  };
1478
1592
  }
1479
1593
 
1480
- function prepareRecommendPipelineStart(args = {}, { workspaceRoot = "" } = {}) {
1481
- const parsed = parseRecommendPipelineRequest(args);
1594
+ function prepareRecommendPipelineStart(args = {}, { workspaceRoot = "" } = {}) {
1595
+ const routeGuard = guardRecommendRoute(args);
1596
+ if (routeGuard) return { response: routeGuard };
1597
+ const parsed = parseRecommendPipelineRequest(args);
1482
1598
  const gate = evaluateRecommendPipelineGate(parsed, args);
1483
1599
  if (gate) return { response: gate };
1484
1600
  const configResolution = resolveBossScreeningConfig(workspaceRoot);