@reconcrap/boss-recommend-mcp 2.0.2 → 2.0.4
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 +3 -3
- package/config/screening-config.example.json +10 -8
- package/package.json +1 -1
- package/skills/boss-chat/SKILL.md +3 -0
- package/skills/boss-recommend-pipeline/SKILL.md +9 -2
- package/skills/boss-recruit-pipeline/SKILL.md +3 -0
- package/src/chat-mcp.js +160 -41
- package/src/chat-runtime-config.js +28 -1
- package/src/core/browser/index.js +392 -0
- package/src/core/screening/index.js +3 -3
- package/src/index.js +4 -2
- package/src/recommend-mcp.js +142 -33
- package/src/recruit-mcp.js +157 -30
package/README.md
CHANGED
|
@@ -221,10 +221,10 @@ config/screening-config.example.json
|
|
|
221
221
|
|
|
222
222
|
- `openaiOrganization`
|
|
223
223
|
- `openaiProject`
|
|
224
|
-
- `debugPort`
|
|
225
|
-
- `outputDir
|
|
224
|
+
- `debugPort`:未显式传 `port` 时,recommend / search / chat CDP-only MCP run 和健康检查默认连接这个 Chrome 调试端口。
|
|
225
|
+
- `outputDir`:recommend / search / chat 完成后的最终 CSV 与 report JSON 会写入这里;run state / checkpoint 仍保留在各自状态目录,方便 pause/resume/cancel。
|
|
226
226
|
- `llmThinkingLevel`:默认 `low`。可设为 `off/minimal/low/medium/high/auto/current`,用于控制 OpenAI-compatible LLM 的 thinking/reasoning 强度。
|
|
227
|
-
- `humanRestEnabled`:默认 `false
|
|
227
|
+
- `humanRestEnabled`:默认 `false`。当前 CDP-only recommend / search / chat run 尚未实现随机休息层,因此会读取并保留该字段但不改变节奏;如后续重新加入 human rest,应以此字段为默认值。
|
|
228
228
|
|
|
229
229
|
## 常用命令
|
|
230
230
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"baseUrl": "https://api.openai.com/v1",
|
|
3
3
|
"apiKey": "replace-with-openai-api-key",
|
|
4
|
-
"model": "gpt-4.1-mini",
|
|
5
|
-
"llmThinkingLevel": "low",
|
|
6
|
-
"llmTimeoutMs": 60000,
|
|
7
|
-
"llmMaxRetries": 3,
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
4
|
+
"model": "gpt-4.1-mini",
|
|
5
|
+
"llmThinkingLevel": "low",
|
|
6
|
+
"llmTimeoutMs": 60000,
|
|
7
|
+
"llmMaxRetries": 3,
|
|
8
|
+
"debugPort": 9222,
|
|
9
|
+
"outputDir": "",
|
|
10
|
+
"humanRestEnabled": false,
|
|
11
|
+
"openaiOrganization": "optional-org-id",
|
|
12
|
+
"openaiProject": "optional-project-id"
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -57,6 +57,9 @@ description: "Use when users want Boss chat-page screening/outreach via the bund
|
|
|
57
57
|
- 只在用户明确是 chat-only 任务时使用本 skill。
|
|
58
58
|
- 只要用户提到推荐页、先找人后沟通、或需要推荐筛选阶段,禁止直接调用 `start_boss_chat_run`;必须先交给 `boss-recommend-pipeline` 完成推荐页任务。
|
|
59
59
|
- 不得在 recommend 任务尚未完成时并行启动独立 chat run。
|
|
60
|
+
- 启动或准备 chat run 时,若本机默认 `127.0.0.1:9222` Chrome DevTools 端口不可连,工具会自动打开 Chrome 并导航到 `https://www.zhipin.com/web/chat/index`。
|
|
61
|
+
- 只有工具返回 `BOSS_LOGIN_REQUIRED` / `requires_login=true` 时,才要求用户在自动打开的 Chrome 窗口人工登录 Boss 后重试;不要把“没开 9222 Chrome”当作缺参。
|
|
62
|
+
- 若本机找不到 Chrome,可提示用户设置 `BOSS_MCP_CHROME_PATH` 或 `BOSS_RECOMMEND_CHROME_PATH`;非本机 debug host 不自动启动。
|
|
60
63
|
- `job` / `start_from` / `criteria` 缺一不可;缺参时只补缺口。
|
|
61
64
|
- `target_count` 在 chat-only 启动前也是必填项,不能默认省略。
|
|
62
65
|
- 当用户说“全部候选人/所有候选人”时,必须按“扫到底(unlimited)”处理,不要再追问正整数。
|
|
@@ -118,8 +118,14 @@ description: "Use when users want Boss recommend-page filtering/screening via bo
|
|
|
118
118
|
|
|
119
119
|
- 执行前必须通过:
|
|
120
120
|
- `screening-config.json` 可用且非占位值(`baseUrl/apiKey/model`)
|
|
121
|
-
- Chrome DevTools
|
|
122
|
-
- Boss
|
|
121
|
+
- 工具可连接或自动启动本机 Chrome DevTools 端口(默认 `127.0.0.1:9222`)
|
|
122
|
+
- Boss 已登录;若当前没有 9222 Chrome,工具会自动打开 Chrome 并导航到 `https://www.zhipin.com/web/chat/recommend`
|
|
123
|
+
- 只有工具返回 `BOSS_LOGIN_REQUIRED` / `requires_login=true` 时,才要求用户人工登录 Boss 后重试
|
|
124
|
+
|
|
125
|
+
- 不要在运行前要求用户手动打开 9222 Chrome。只有这些情况需要人工介入:
|
|
126
|
+
- 工具明确报告 `BOSS_LOGIN_REQUIRED`
|
|
127
|
+
- 本机找不到 Chrome 可执行文件,并提示设置 `BOSS_MCP_CHROME_PATH` 或 `BOSS_RECOMMEND_CHROME_PATH`
|
|
128
|
+
- 用户配置的是非本机 debug host,工具无法安全自动启动
|
|
123
129
|
|
|
124
130
|
- `PIPELINE_PREFLIGHT_FAILED` 处理顺序:
|
|
125
131
|
1. 若 `screen_config` 失败:让用户提供真实 `baseUrl/apiKey/model`,并在 `guidance.config_path` 修改后明确回复“已修改完成”。
|
|
@@ -153,3 +159,4 @@ MCP 不可用时:
|
|
|
153
159
|
- 页面就绪失败提示必须包含 `debug_port`、recommend URL、以及登录 URL(若未登录):
|
|
154
160
|
- `https://www.zhipin.com/web/chat/recommend`
|
|
155
161
|
- `https://www.zhipin.com/web/user/?ka=bticket`
|
|
162
|
+
- 若错误是 `BOSS_LOGIN_REQUIRED`,提示用户在自动打开的 Chrome 窗口完成登录,然后原参数重试;不要改用 search/recruit 路径。
|
|
@@ -25,6 +25,9 @@ description: "Use when users want Boss search/recruit-page screening via the uni
|
|
|
25
25
|
- 如果用户说聊天页、未读、全部聊天、求简历,必须交给 `boss-chat`。
|
|
26
26
|
- 禁止调用旧包:`@reconcrap/boss-recruit-mcp`、`boss-recruit-mcp`、旧本地 recruit repo、旧 vendor 脚本。
|
|
27
27
|
- 浏览器自动化必须走 CDP-only 2.x MCP 工具;不得要求用户启用 legacy page-JS 或 `Runtime.evaluate` 路径。
|
|
28
|
+
- 启动 search/recruit run 时,若本机默认 `127.0.0.1:9222` Chrome DevTools 端口不可连,工具会自动打开 Chrome 并导航到 `https://www.zhipin.com/web/chat/search`。
|
|
29
|
+
- 只有工具返回 `BOSS_LOGIN_REQUIRED` / `requires_login=true` 时,才要求用户在自动打开的 Chrome 窗口人工登录 Boss 后重试;不要把“没开 9222 Chrome”当作缺参。
|
|
30
|
+
- 若本机找不到 Chrome,可提示用户设置 `BOSS_MCP_CHROME_PATH` 或 `BOSS_RECOMMEND_CHROME_PATH`;非本机 debug host 不自动启动。
|
|
28
31
|
- 若用户未提供岗位,必须先询问岗位。搜索页岗位选择在关键词输入框旁边;不要猜测默认岗位。
|
|
29
32
|
- 若用户提供城市、学历、学校、关键词、过滤已看、人选目标数、筛选条件、post action、max greet 等参数,必须逐项传入或确认。
|
|
30
33
|
- `post_action=greet` 时必须确认 `max_greet_count`;不要默认等于 `target_count`。
|
package/src/chat-mcp.js
CHANGED
|
@@ -4,8 +4,13 @@ import process from "node:process";
|
|
|
4
4
|
import {
|
|
5
5
|
assertNoForbiddenCdpCalls,
|
|
6
6
|
bringPageToFront,
|
|
7
|
-
|
|
7
|
+
connectToChromeTargetOrOpen,
|
|
8
|
+
createBossLoginRequiredError,
|
|
9
|
+
detectBossLoginState,
|
|
8
10
|
enableDomains,
|
|
11
|
+
getMainFrameUrl,
|
|
12
|
+
isBossLoginUrl,
|
|
13
|
+
waitForMainFrameUrl,
|
|
9
14
|
sleep
|
|
10
15
|
} from "./core/browser/index.js";
|
|
11
16
|
import {
|
|
@@ -40,6 +45,7 @@ import {
|
|
|
40
45
|
getBossChatDataDir,
|
|
41
46
|
getBossChatTargetCountValue,
|
|
42
47
|
normalizeTargetCountInput,
|
|
48
|
+
resolveBossConfiguredOutputDir,
|
|
43
49
|
resolveBossChatRuntimeLayout,
|
|
44
50
|
resolveBossScreeningConfig
|
|
45
51
|
} from "./chat-runtime-config.js";
|
|
@@ -118,12 +124,14 @@ function getChatRunArtifacts(runId) {
|
|
|
118
124
|
const normalized = normalizeRunId(runId);
|
|
119
125
|
if (!normalized) return null;
|
|
120
126
|
const runsDir = getChatRunsDir();
|
|
127
|
+
const outputDir = resolveBossConfiguredOutputDir("", runsDir);
|
|
121
128
|
return {
|
|
122
129
|
runs_dir: runsDir,
|
|
130
|
+
output_dir: outputDir,
|
|
123
131
|
run_state_path: path.join(runsDir, `${normalized}.json`),
|
|
124
132
|
checkpoint_path: path.join(runsDir, `${normalized}.checkpoint.json`),
|
|
125
|
-
output_csv: path.join(
|
|
126
|
-
report_json: path.join(
|
|
133
|
+
output_csv: path.join(outputDir, `${normalized}.results.csv`),
|
|
134
|
+
report_json: path.join(outputDir, `${normalized}.report.json`)
|
|
127
135
|
};
|
|
128
136
|
}
|
|
129
137
|
|
|
@@ -472,6 +480,14 @@ async function waitForHealthyChat(client, config, {
|
|
|
472
480
|
const started = Date.now();
|
|
473
481
|
let lastCheck = null;
|
|
474
482
|
while (Date.now() - started <= timeoutMs) {
|
|
483
|
+
const loginDetection = await detectBossLoginState(client).catch(() => null);
|
|
484
|
+
if (loginDetection?.requires_login) {
|
|
485
|
+
return {
|
|
486
|
+
status: "login_required",
|
|
487
|
+
summary: "Boss login is required",
|
|
488
|
+
loginDetection
|
|
489
|
+
};
|
|
490
|
+
}
|
|
475
491
|
const roots = await resolveChatSelfHealRoots(client, config);
|
|
476
492
|
lastCheck = await runSelfHealCheck({
|
|
477
493
|
client,
|
|
@@ -493,24 +509,18 @@ async function connectChatChromeSession({
|
|
|
493
509
|
allowNavigate = true,
|
|
494
510
|
slowLive = false
|
|
495
511
|
} = {}) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
targetPredicate: (target) => (
|
|
509
|
-
target?.type === "page"
|
|
510
|
-
&& isRecoverableChatTargetUrl(target?.url)
|
|
511
|
-
)
|
|
512
|
-
});
|
|
513
|
-
}
|
|
512
|
+
const session = await connectToChromeTargetOrOpen({
|
|
513
|
+
host,
|
|
514
|
+
port,
|
|
515
|
+
targetUrlIncludes,
|
|
516
|
+
targetUrl: CHAT_TARGET_URL,
|
|
517
|
+
allowNavigate,
|
|
518
|
+
slowLive,
|
|
519
|
+
fallbackTargetPredicate: (target) => (
|
|
520
|
+
target?.type === "page"
|
|
521
|
+
&& (isRecoverableChatTargetUrl(target?.url) || String(target?.url || "").includes("zhipin.com"))
|
|
522
|
+
)
|
|
523
|
+
});
|
|
514
524
|
|
|
515
525
|
const { client, target } = session;
|
|
516
526
|
await enableDomains(client, ["Page", "DOM", "Input", "Network", "Accessibility"]);
|
|
@@ -527,20 +537,90 @@ async function connectChatChromeSession({
|
|
|
527
537
|
if (allowNavigate && shouldNavigateToChat(targetUrl)) {
|
|
528
538
|
await client.Page.navigate({ url: CHAT_TARGET_URL });
|
|
529
539
|
const settleMs = slowLive ? 10000 : 5000;
|
|
530
|
-
await
|
|
540
|
+
const waited = await waitForMainFrameUrl(
|
|
541
|
+
client,
|
|
542
|
+
(url) => isBossLoginUrl(url) || !shouldNavigateToChat(url),
|
|
543
|
+
{ timeoutMs: settleMs, intervalMs: 500 }
|
|
544
|
+
);
|
|
531
545
|
navigation = {
|
|
532
546
|
navigated: true,
|
|
533
547
|
url: CHAT_TARGET_URL,
|
|
534
|
-
settle_ms: settleMs
|
|
548
|
+
settle_ms: settleMs,
|
|
549
|
+
observed_url: waited.url || null,
|
|
550
|
+
observed_url_ok: waited.ok
|
|
535
551
|
};
|
|
536
552
|
}
|
|
553
|
+
let currentUrl = await getMainFrameUrl(client).catch(() => navigation.url || targetUrl);
|
|
554
|
+
if (allowNavigate && shouldNavigateToChat(currentUrl) && !isBossLoginUrl(currentUrl)) {
|
|
555
|
+
await client.Page.navigate({ url: CHAT_TARGET_URL });
|
|
556
|
+
const settleMs = slowLive ? 10000 : 5000;
|
|
557
|
+
const waited = await waitForMainFrameUrl(
|
|
558
|
+
client,
|
|
559
|
+
(url) => isBossLoginUrl(url) || !shouldNavigateToChat(url),
|
|
560
|
+
{ timeoutMs: settleMs, intervalMs: 500 }
|
|
561
|
+
);
|
|
562
|
+
navigation = {
|
|
563
|
+
navigated: true,
|
|
564
|
+
url: CHAT_TARGET_URL,
|
|
565
|
+
settle_ms: settleMs,
|
|
566
|
+
observed_url: waited.url || null,
|
|
567
|
+
observed_url_ok: waited.ok,
|
|
568
|
+
reason: "observed_url_mismatch"
|
|
569
|
+
};
|
|
570
|
+
currentUrl = await getMainFrameUrl(client).catch(() => waited.url || currentUrl);
|
|
571
|
+
}
|
|
572
|
+
const loginDetection = await detectBossLoginState(client, { currentUrl }).catch(() => ({
|
|
573
|
+
requires_login: isBossLoginUrl(currentUrl),
|
|
574
|
+
reason: "login_detection_failed",
|
|
575
|
+
current_url: currentUrl
|
|
576
|
+
}));
|
|
577
|
+
if (loginDetection.requires_login) {
|
|
578
|
+
await session.close?.();
|
|
579
|
+
throw createBossLoginRequiredError({
|
|
580
|
+
domain: "chat",
|
|
581
|
+
currentUrl: loginDetection.current_url || currentUrl,
|
|
582
|
+
targetUrl: CHAT_TARGET_URL,
|
|
583
|
+
loginDetection,
|
|
584
|
+
chrome: session.chrome || null
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
if (shouldNavigateToChat(currentUrl)) {
|
|
588
|
+
await session.close?.();
|
|
589
|
+
throw new Error(`Boss chat page did not navigate to ${CHAT_TARGET_URL}; current URL: ${currentUrl || "unknown"}`);
|
|
590
|
+
}
|
|
537
591
|
|
|
538
592
|
const selfHealConfig = buildChatSelfHealConfig();
|
|
539
593
|
const health = await waitForHealthyChat(client, selfHealConfig, {
|
|
540
594
|
timeoutMs: slowLive ? 180000 : 90000,
|
|
541
595
|
intervalMs: slowLive ? 1200 : 800
|
|
542
596
|
});
|
|
597
|
+
if (health?.loginDetection?.requires_login) {
|
|
598
|
+
await session.close?.();
|
|
599
|
+
throw createBossLoginRequiredError({
|
|
600
|
+
domain: "chat",
|
|
601
|
+
currentUrl: health.loginDetection.current_url || currentUrl,
|
|
602
|
+
targetUrl: CHAT_TARGET_URL,
|
|
603
|
+
loginDetection: health.loginDetection,
|
|
604
|
+
chrome: session.chrome || null
|
|
605
|
+
});
|
|
606
|
+
}
|
|
543
607
|
if (!health || health.status !== HEALTH_STATUS.HEALTHY) {
|
|
608
|
+
const latestUrl = await getMainFrameUrl(client).catch(() => currentUrl);
|
|
609
|
+
const latestLoginDetection = await detectBossLoginState(client, { currentUrl: latestUrl }).catch(() => ({
|
|
610
|
+
requires_login: isBossLoginUrl(latestUrl),
|
|
611
|
+
reason: "login_detection_failed",
|
|
612
|
+
current_url: latestUrl
|
|
613
|
+
}));
|
|
614
|
+
if (latestLoginDetection.requires_login) {
|
|
615
|
+
await session.close?.();
|
|
616
|
+
throw createBossLoginRequiredError({
|
|
617
|
+
domain: "chat",
|
|
618
|
+
currentUrl: latestLoginDetection.current_url || latestUrl,
|
|
619
|
+
targetUrl: CHAT_TARGET_URL,
|
|
620
|
+
loginDetection: latestLoginDetection,
|
|
621
|
+
chrome: session.chrome || null
|
|
622
|
+
});
|
|
623
|
+
}
|
|
544
624
|
throw new Error(`Boss chat page is not healthy: ${health?.status || "missing"}`);
|
|
545
625
|
}
|
|
546
626
|
|
|
@@ -556,7 +636,7 @@ async function readChatJobOptionsFromSession(session) {
|
|
|
556
636
|
return readChatJobOptions(session.client, roots.rootNodes.top);
|
|
557
637
|
}
|
|
558
638
|
|
|
559
|
-
function normalizeChatStartInput(args = {}) {
|
|
639
|
+
function normalizeChatStartInput(args = {}, configResolution = null) {
|
|
560
640
|
const target = normalizeTargetCountInput(getBossChatTargetCountValue(args));
|
|
561
641
|
return {
|
|
562
642
|
profile: normalizeText(args.profile) || "default",
|
|
@@ -568,7 +648,10 @@ function normalizeChatStartInput(args = {}) {
|
|
|
568
648
|
targetCount: target.targetCount,
|
|
569
649
|
publicTargetCount: target.publicValue,
|
|
570
650
|
host: normalizeText(args.host) || DEFAULT_CHAT_HOST,
|
|
571
|
-
port: parsePositiveInteger(
|
|
651
|
+
port: parsePositiveInteger(
|
|
652
|
+
args.port,
|
|
653
|
+
configResolution?.ok ? configResolution.config.debugPort : DEFAULT_CHAT_PORT
|
|
654
|
+
),
|
|
572
655
|
targetUrlIncludes: normalizeText(args.target_url_includes) || CHAT_TARGET_URL,
|
|
573
656
|
allowNavigate: args.allow_navigate !== false,
|
|
574
657
|
slowLive: args.slow_live === true
|
|
@@ -723,7 +806,6 @@ function getRunOptions(args, normalized, session, { workspaceRoot = "" } = {}) {
|
|
|
723
806
|
const shouldRequestResume = shouldRequestChatResume(args);
|
|
724
807
|
const useLlm = shouldUseChatLlm(args, shouldRequestResume);
|
|
725
808
|
const configResolution = useLlm ? resolveBossScreeningConfig(workspaceRoot) : { ok: false };
|
|
726
|
-
const configFile = configResolution.ok ? readJsonFile(configResolution.config_path) : null;
|
|
727
809
|
return {
|
|
728
810
|
client: session.client,
|
|
729
811
|
targetUrl: CHAT_TARGET_URL,
|
|
@@ -750,8 +832,7 @@ function getRunOptions(args, normalized, session, { workspaceRoot = "" } = {}) {
|
|
|
750
832
|
maxImagePages: parsePositiveInteger(args.max_image_pages, 8),
|
|
751
833
|
imageWheelDeltaY: parsePositiveInteger(args.image_wheel_delta_y, 650),
|
|
752
834
|
llmConfig: configResolution.ok ? {
|
|
753
|
-
...configResolution.config
|
|
754
|
-
apiKey: configFile?.apiKey || ""
|
|
835
|
+
...configResolution.config
|
|
755
836
|
} : null,
|
|
756
837
|
llmTimeoutMs: parsePositiveInteger(args.llm_timeout_ms, slowLive ? 180000 : 120000),
|
|
757
838
|
llmImageLimit: parsePositiveInteger(args.llm_image_limit, 8),
|
|
@@ -811,7 +892,8 @@ function trackChatRun(runId) {
|
|
|
811
892
|
}
|
|
812
893
|
|
|
813
894
|
async function startBossChatRunInternal(args = {}, { workspaceRoot = "" } = {}) {
|
|
814
|
-
const
|
|
895
|
+
const defaultConfigResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
896
|
+
const normalized = normalizeChatStartInput(args, defaultConfigResolution);
|
|
815
897
|
const missingFields = getMissingChatStartFields(args, normalized);
|
|
816
898
|
if (missingFields.length) {
|
|
817
899
|
return buildNeedInputResponse({
|
|
@@ -845,13 +927,21 @@ async function startBossChatRunInternal(args = {}, { workspaceRoot = "" } = {})
|
|
|
845
927
|
slowLive: normalized.slowLive
|
|
846
928
|
});
|
|
847
929
|
} catch (error) {
|
|
930
|
+
const loginRequired = error?.code === "BOSS_LOGIN_REQUIRED";
|
|
848
931
|
return {
|
|
849
932
|
status: "FAILED",
|
|
850
933
|
error: {
|
|
851
|
-
code: "BOSS_CHAT_PAGE_NOT_READY",
|
|
934
|
+
code: loginRequired ? "BOSS_LOGIN_REQUIRED" : "BOSS_CHAT_PAGE_NOT_READY",
|
|
852
935
|
message: error?.message || "Boss chat page is not ready",
|
|
936
|
+
requires_login: Boolean(error?.requires_login),
|
|
937
|
+
login_url: error?.login_url || null,
|
|
938
|
+
login_detection: error?.login_detection || null,
|
|
939
|
+
chrome: error?.chrome || null,
|
|
940
|
+
current_url: error?.current_url || null,
|
|
941
|
+
target_url: error?.target_url || CHAT_TARGET_URL,
|
|
853
942
|
retryable: true
|
|
854
|
-
}
|
|
943
|
+
},
|
|
944
|
+
chrome: error?.chrome || null
|
|
855
945
|
};
|
|
856
946
|
}
|
|
857
947
|
|
|
@@ -880,7 +970,8 @@ async function startBossChatRunInternal(args = {}, { workspaceRoot = "" } = {})
|
|
|
880
970
|
host: normalized.host,
|
|
881
971
|
port: normalized.port,
|
|
882
972
|
target_url: session.navigation?.url || session.target?.url || CHAT_TARGET_URL,
|
|
883
|
-
target_id: session.target?.id || null
|
|
973
|
+
target_id: session.target?.id || null,
|
|
974
|
+
auto_launch: session.chrome || null
|
|
884
975
|
},
|
|
885
976
|
health: session.health || null
|
|
886
977
|
});
|
|
@@ -901,7 +992,8 @@ async function startBossChatRunInternal(args = {}, { workspaceRoot = "" } = {})
|
|
|
901
992
|
}
|
|
902
993
|
|
|
903
994
|
export async function prepareBossChatRunTool({ workspaceRoot = "", args = {} } = {}) {
|
|
904
|
-
const
|
|
995
|
+
const configResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
996
|
+
const normalized = normalizeChatStartInput(args, configResolution);
|
|
905
997
|
let session;
|
|
906
998
|
try {
|
|
907
999
|
session = await chatConnectorImpl({
|
|
@@ -912,12 +1004,19 @@ export async function prepareBossChatRunTool({ workspaceRoot = "", args = {} } =
|
|
|
912
1004
|
slowLive: normalized.slowLive
|
|
913
1005
|
});
|
|
914
1006
|
} catch (error) {
|
|
1007
|
+
const loginRequired = error?.code === "BOSS_LOGIN_REQUIRED";
|
|
915
1008
|
return {
|
|
916
1009
|
status: "FAILED",
|
|
917
1010
|
stage: "chat_run_setup",
|
|
918
1011
|
error: {
|
|
919
|
-
code: "BOSS_CHAT_PAGE_NOT_READY",
|
|
1012
|
+
code: loginRequired ? "BOSS_LOGIN_REQUIRED" : "BOSS_CHAT_PAGE_NOT_READY",
|
|
920
1013
|
message: error?.message || "Boss chat page is not ready",
|
|
1014
|
+
requires_login: Boolean(error?.requires_login),
|
|
1015
|
+
login_url: error?.login_url || null,
|
|
1016
|
+
login_detection: error?.login_detection || null,
|
|
1017
|
+
chrome: error?.chrome || null,
|
|
1018
|
+
current_url: error?.current_url || null,
|
|
1019
|
+
target_url: error?.target_url || CHAT_TARGET_URL,
|
|
921
1020
|
retryable: true
|
|
922
1021
|
},
|
|
923
1022
|
runtime_evaluate_used: false,
|
|
@@ -926,7 +1025,8 @@ export async function prepareBossChatRunTool({ workspaceRoot = "", args = {} } =
|
|
|
926
1025
|
chrome: {
|
|
927
1026
|
host: normalized.host,
|
|
928
1027
|
port: normalized.port,
|
|
929
|
-
target_url: CHAT_TARGET_URL
|
|
1028
|
+
target_url: CHAT_TARGET_URL,
|
|
1029
|
+
auto_launch: error?.chrome || null
|
|
930
1030
|
}
|
|
931
1031
|
};
|
|
932
1032
|
}
|
|
@@ -979,16 +1079,24 @@ export async function prepareBossChatRunTool({ workspaceRoot = "", args = {} } =
|
|
|
979
1079
|
host: normalized.host,
|
|
980
1080
|
port: normalized.port,
|
|
981
1081
|
target_url: session.navigation?.url || session.target?.url || CHAT_TARGET_URL,
|
|
982
|
-
target_id: session.target?.id || null
|
|
1082
|
+
target_id: session.target?.id || null,
|
|
1083
|
+
auto_launch: session.chrome || null
|
|
983
1084
|
}
|
|
984
1085
|
};
|
|
985
1086
|
} catch (error) {
|
|
1087
|
+
const loginRequired = error?.code === "BOSS_LOGIN_REQUIRED";
|
|
986
1088
|
return {
|
|
987
1089
|
status: "FAILED",
|
|
988
1090
|
stage: "chat_run_setup",
|
|
989
1091
|
error: {
|
|
990
|
-
code: "BOSS_CHAT_PREPARE_FAILED",
|
|
1092
|
+
code: loginRequired ? "BOSS_LOGIN_REQUIRED" : "BOSS_CHAT_PREPARE_FAILED",
|
|
991
1093
|
message: error?.message || "Boss chat CDP-only prepare failed",
|
|
1094
|
+
requires_login: Boolean(error?.requires_login),
|
|
1095
|
+
login_url: error?.login_url || null,
|
|
1096
|
+
login_detection: error?.login_detection || null,
|
|
1097
|
+
chrome: error?.chrome || null,
|
|
1098
|
+
current_url: error?.current_url || null,
|
|
1099
|
+
target_url: error?.target_url || CHAT_TARGET_URL,
|
|
992
1100
|
retryable: true
|
|
993
1101
|
},
|
|
994
1102
|
runtime_evaluate_used: false,
|
|
@@ -998,7 +1106,8 @@ export async function prepareBossChatRunTool({ workspaceRoot = "", args = {} } =
|
|
|
998
1106
|
host: normalized.host,
|
|
999
1107
|
port: normalized.port,
|
|
1000
1108
|
target_url: session.navigation?.url || session.target?.url || CHAT_TARGET_URL,
|
|
1001
|
-
target_id: session.target?.id || null
|
|
1109
|
+
target_id: session.target?.id || null,
|
|
1110
|
+
auto_launch: session.chrome || null
|
|
1002
1111
|
}
|
|
1003
1112
|
};
|
|
1004
1113
|
} finally {
|
|
@@ -1026,6 +1135,7 @@ export async function bossChatHealthCheckTool({ workspaceRoot = "", args = {} }
|
|
|
1026
1135
|
cli_path: null,
|
|
1027
1136
|
config_path: configResolution.config_path || null,
|
|
1028
1137
|
config_dir: configResolution.config_dir || null,
|
|
1138
|
+
output_dir: configResolution.ok ? configResolution.config.outputDir || null : null,
|
|
1029
1139
|
debug_port: port,
|
|
1030
1140
|
shared_llm_config: configResolution.ok === true,
|
|
1031
1141
|
data_dir: runtimeLayout.data_dir,
|
|
@@ -1073,17 +1183,25 @@ export async function bossChatHealthCheckTool({ workspaceRoot = "", args = {} }
|
|
|
1073
1183
|
host,
|
|
1074
1184
|
port,
|
|
1075
1185
|
target_url: session.navigation?.url || session.target?.url || CHAT_TARGET_URL,
|
|
1076
|
-
target_id: session.target?.id || null
|
|
1186
|
+
target_id: session.target?.id || null,
|
|
1187
|
+
auto_launch: session.chrome || null
|
|
1077
1188
|
},
|
|
1078
1189
|
message: "Boss chat CDP-only health check passed with shared self-heal probes."
|
|
1079
1190
|
};
|
|
1080
1191
|
} catch (error) {
|
|
1192
|
+
const loginRequired = error?.code === "BOSS_LOGIN_REQUIRED";
|
|
1081
1193
|
return {
|
|
1082
1194
|
status: "FAILED",
|
|
1083
1195
|
...basePayload,
|
|
1084
1196
|
error: {
|
|
1085
|
-
code: "BOSS_CHAT_PAGE_NOT_READY",
|
|
1197
|
+
code: loginRequired ? "BOSS_LOGIN_REQUIRED" : "BOSS_CHAT_PAGE_NOT_READY",
|
|
1086
1198
|
message: error?.message || "Boss chat page is not ready",
|
|
1199
|
+
requires_login: Boolean(error?.requires_login),
|
|
1200
|
+
login_url: error?.login_url || null,
|
|
1201
|
+
login_detection: error?.login_detection || null,
|
|
1202
|
+
chrome: error?.chrome || null,
|
|
1203
|
+
current_url: error?.current_url || null,
|
|
1204
|
+
target_url: error?.target_url || CHAT_TARGET_URL,
|
|
1087
1205
|
retryable: true
|
|
1088
1206
|
},
|
|
1089
1207
|
runtime_evaluate_used: false,
|
|
@@ -1093,7 +1211,8 @@ export async function bossChatHealthCheckTool({ workspaceRoot = "", args = {} }
|
|
|
1093
1211
|
host,
|
|
1094
1212
|
port,
|
|
1095
1213
|
target_url: session?.navigation?.url || session?.target?.url || targetUrlIncludes,
|
|
1096
|
-
target_id: session?.target?.id || null
|
|
1214
|
+
target_id: session?.target?.id || null,
|
|
1215
|
+
auto_launch: error?.chrome || session?.chrome || null
|
|
1097
1216
|
}
|
|
1098
1217
|
};
|
|
1099
1218
|
} finally {
|
|
@@ -223,6 +223,22 @@ function parsePositiveInteger(raw, fallback = null) {
|
|
|
223
223
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
function parseConfigBoolean(raw, fallback = false) {
|
|
227
|
+
if (typeof raw === "boolean") return raw;
|
|
228
|
+
const normalized = normalizeText(raw).toLowerCase();
|
|
229
|
+
if (["true", "1", "yes", "y", "on", "enabled"].includes(normalized)) return true;
|
|
230
|
+
if (["false", "0", "no", "n", "off", "disabled"].includes(normalized)) return false;
|
|
231
|
+
return fallback;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function resolveConfigPathValue(raw, configDir) {
|
|
235
|
+
const normalized = normalizeText(raw);
|
|
236
|
+
if (!normalized) return "";
|
|
237
|
+
return path.isAbsolute(normalized)
|
|
238
|
+
? path.resolve(normalized)
|
|
239
|
+
: path.resolve(configDir || process.cwd(), normalized);
|
|
240
|
+
}
|
|
241
|
+
|
|
226
242
|
function validateScreeningConfig(config) {
|
|
227
243
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
228
244
|
return {
|
|
@@ -369,8 +385,12 @@ export function resolveBossScreeningConfig(workspaceRoot) {
|
|
|
369
385
|
ok: true,
|
|
370
386
|
config: {
|
|
371
387
|
baseUrl: normalizeText(parsed.baseUrl).replace(/\/+$/, ""),
|
|
388
|
+
apiKey: normalizeText(parsed.apiKey),
|
|
372
389
|
model: normalizeText(parsed.model),
|
|
373
|
-
debugPort: parsePositiveInteger(parsed.debugPort, 9222)
|
|
390
|
+
debugPort: parsePositiveInteger(parsed.debugPort, 9222),
|
|
391
|
+
llmThinkingLevel: normalizeText(parsed.llmThinkingLevel || parsed.thinkingLevel || parsed.reasoningEffort),
|
|
392
|
+
outputDir: resolveConfigPathValue(parsed.outputDir, configDir),
|
|
393
|
+
humanRestEnabled: parseConfigBoolean(parsed.humanRestEnabled, false)
|
|
374
394
|
},
|
|
375
395
|
config_path: configPath,
|
|
376
396
|
config_dir: configDir,
|
|
@@ -378,6 +398,13 @@ export function resolveBossScreeningConfig(workspaceRoot) {
|
|
|
378
398
|
};
|
|
379
399
|
}
|
|
380
400
|
|
|
401
|
+
export function resolveBossConfiguredOutputDir(workspaceRoot, fallbackDir = "") {
|
|
402
|
+
const configResolution = resolveBossScreeningConfig(workspaceRoot);
|
|
403
|
+
const configuredDir = configResolution.ok ? normalizeText(configResolution.config.outputDir) : "";
|
|
404
|
+
if (configuredDir) return configuredDir;
|
|
405
|
+
return fallbackDir ? path.resolve(fallbackDir) : "";
|
|
406
|
+
}
|
|
407
|
+
|
|
381
408
|
function isUnlimitedTargetCountToken(value) {
|
|
382
409
|
const token = normalizeText(value).toLowerCase();
|
|
383
410
|
if (!token) return false;
|