@reconcrap/boss-recommend-mcp 2.0.11 → 2.0.13
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/package.json +1 -1
- package/src/chat-mcp.js +256 -23
- package/src/cli.js +2 -8
- package/src/core/browser/index.js +35 -8
- package/src/core/capture/index.js +323 -20
- package/src/core/cv-acquisition/index.js +3 -0
- package/src/core/infinite-list/index.js +354 -1
- package/src/domains/chat/constants.js +11 -0
- package/src/domains/chat/run-service.js +21 -5
- package/src/domains/recommend/constants.js +11 -0
- package/src/domains/recommend/run-service.js +57 -16
- package/src/domains/recruit/constants.js +23 -0
- package/src/domains/recruit/run-service.js +19 -4
package/package.json
CHANGED
package/src/chat-mcp.js
CHANGED
|
@@ -71,6 +71,43 @@ const TERMINAL_STATUSES = new Set([
|
|
|
71
71
|
RUN_STATUS_CANCELED
|
|
72
72
|
]);
|
|
73
73
|
|
|
74
|
+
const ARTIFACT_STATUSES = new Set([
|
|
75
|
+
RUN_STATUS_COMPLETED,
|
|
76
|
+
RUN_STATUS_FAILED,
|
|
77
|
+
RUN_STATUS_CANCELED,
|
|
78
|
+
RUN_STATUS_PAUSED
|
|
79
|
+
]);
|
|
80
|
+
|
|
81
|
+
const STALE_PROCESS_STATUSES = new Set([
|
|
82
|
+
"queued",
|
|
83
|
+
"running",
|
|
84
|
+
RUN_STATUS_CANCELING
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const CHAT_REQUEST_RESUME_ACTIONS = new Set([
|
|
88
|
+
"request_cv",
|
|
89
|
+
"ask_cv",
|
|
90
|
+
"request_resume",
|
|
91
|
+
"求简历",
|
|
92
|
+
"索要简历"
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
const CHAT_DISABLE_REQUEST_RESUME_ACTIONS = new Set([
|
|
96
|
+
"none",
|
|
97
|
+
"no",
|
|
98
|
+
"false",
|
|
99
|
+
"off",
|
|
100
|
+
"skip",
|
|
101
|
+
"do_nothing",
|
|
102
|
+
"nothing",
|
|
103
|
+
"不做",
|
|
104
|
+
"什么都不做",
|
|
105
|
+
"无",
|
|
106
|
+
"不用",
|
|
107
|
+
"不求简历",
|
|
108
|
+
"不请求简历"
|
|
109
|
+
]);
|
|
110
|
+
|
|
74
111
|
let chatWorkflowImpl = runChatWorkflow;
|
|
75
112
|
let chatConnectorImpl = connectChatChromeSession;
|
|
76
113
|
let chatJobReaderImpl = readChatJobOptionsFromSession;
|
|
@@ -156,8 +193,13 @@ function readJsonFile(filePath) {
|
|
|
156
193
|
}
|
|
157
194
|
}
|
|
158
195
|
|
|
159
|
-
function selectedChatJobForCsv(meta = {}) {
|
|
160
|
-
const job = normalizeText(
|
|
196
|
+
function selectedChatJobForCsv(meta = {}, snapshot = {}) {
|
|
197
|
+
const job = normalizeText(
|
|
198
|
+
meta.normalized?.job
|
|
199
|
+
|| meta.args?.job
|
|
200
|
+
|| snapshot.context?.job
|
|
201
|
+
|| ""
|
|
202
|
+
);
|
|
161
203
|
return {
|
|
162
204
|
value: job,
|
|
163
205
|
title: job,
|
|
@@ -167,31 +209,32 @@ function selectedChatJobForCsv(meta = {}) {
|
|
|
167
209
|
|
|
168
210
|
function buildChatCsvInputRows(snapshot = {}, meta = {}) {
|
|
169
211
|
const normalized = meta.normalized || {};
|
|
170
|
-
const
|
|
212
|
+
const context = snapshot.context || {};
|
|
213
|
+
const postAction = shouldRequestChatResume(meta.args, context)
|
|
171
214
|
? "request_cv"
|
|
172
215
|
: normalizeText(meta.args?.post_action || meta.args?.action || "") || "none";
|
|
173
216
|
const searchParams = {
|
|
174
|
-
job: normalized.job || meta.args?.job || "",
|
|
175
|
-
start_from: normalized.startFrom || meta.args?.start_from || "",
|
|
217
|
+
job: normalized.job || meta.args?.job || context.job || "",
|
|
218
|
+
start_from: normalized.startFrom || meta.args?.start_from || context.start_from || "",
|
|
176
219
|
target_count: normalized.publicTargetCount ?? normalized.targetCount ?? snapshot.progress?.target_count ?? "",
|
|
177
|
-
detail_source: meta.args?.detail_source || snapshot.summary?.detail_source ||
|
|
220
|
+
detail_source: meta.args?.detail_source || snapshot.summary?.detail_source || context.detail_source || ""
|
|
178
221
|
};
|
|
179
222
|
return buildLegacyScreenInputRows({
|
|
180
223
|
instruction: meta.args?.instruction || "启动boss聊天任务",
|
|
181
224
|
selectedPage: "chat",
|
|
182
|
-
selectedJob: selectedChatJobForCsv(meta),
|
|
225
|
+
selectedJob: selectedChatJobForCsv(meta, snapshot),
|
|
183
226
|
userSearchParams: cloneReportInput(searchParams, {}),
|
|
184
227
|
effectiveSearchParams: cloneReportInput(searchParams, {}),
|
|
185
228
|
screenParams: {
|
|
186
|
-
criteria: normalized.criteria || meta.args?.criteria || "",
|
|
229
|
+
criteria: normalized.criteria || meta.args?.criteria || context.criteria || "",
|
|
187
230
|
target_count: searchParams.target_count,
|
|
188
231
|
post_action: postAction,
|
|
189
232
|
max_greet_count: meta.args?.max_greet_count ?? ""
|
|
190
233
|
},
|
|
191
234
|
followUp: meta.args?.follow_up || null,
|
|
192
235
|
extraRows: [
|
|
193
|
-
["chat_params.greeting_text", normalized.greetingText || meta.args?.greeting_text || meta.args?.greetingText || DEFAULT_CHAT_GREETING_TEXT],
|
|
194
|
-
["chat_params.profile", normalized.profile || meta.args?.profile || "default"]
|
|
236
|
+
["chat_params.greeting_text", normalized.greetingText || meta.args?.greeting_text || meta.args?.greetingText || context.greeting_text || DEFAULT_CHAT_GREETING_TEXT],
|
|
237
|
+
["chat_params.profile", normalized.profile || meta.args?.profile || context.profile || "default"]
|
|
195
238
|
]
|
|
196
239
|
});
|
|
197
240
|
}
|
|
@@ -314,6 +357,12 @@ function ensureChatRunArtifacts(snapshot) {
|
|
|
314
357
|
partial: true,
|
|
315
358
|
partial_reason: snapshot?.status || snapshot?.state || "non_terminal",
|
|
316
359
|
results: checkpointResults
|
|
360
|
+
} : ARTIFACT_STATUSES.has(snapshot?.status || snapshot?.state) ? {
|
|
361
|
+
domain: "chat",
|
|
362
|
+
partial: (snapshot?.status || snapshot?.state) !== RUN_STATUS_COMPLETED,
|
|
363
|
+
partial_reason: snapshot?.status || snapshot?.state || "unknown",
|
|
364
|
+
completion_reason: completionReason(snapshot?.status || snapshot?.state),
|
|
365
|
+
results: []
|
|
317
366
|
} : null);
|
|
318
367
|
if (artifactSummary) {
|
|
319
368
|
const rows = Array.isArray(artifactSummary.results) ? artifactSummary.results : [];
|
|
@@ -337,6 +386,143 @@ function ensureChatRunArtifacts(snapshot) {
|
|
|
337
386
|
return artifacts;
|
|
338
387
|
}
|
|
339
388
|
|
|
389
|
+
function isPidAlive(pid) {
|
|
390
|
+
const numericPid = Number(pid);
|
|
391
|
+
if (!Number.isInteger(numericPid) || numericPid <= 0) return false;
|
|
392
|
+
if (numericPid === process.pid) return true;
|
|
393
|
+
try {
|
|
394
|
+
process.kill(numericPid, 0);
|
|
395
|
+
return true;
|
|
396
|
+
} catch (error) {
|
|
397
|
+
return error?.code === "EPERM";
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function snapshotFromPersistedChatRun(persisted = {}) {
|
|
402
|
+
return {
|
|
403
|
+
runId: persisted.run_id || persisted.runId,
|
|
404
|
+
name: persisted.name || persisted.run_id || persisted.runId,
|
|
405
|
+
status: persisted.status || persisted.state,
|
|
406
|
+
phase: persisted.stage || persisted.phase,
|
|
407
|
+
progress: persisted.progress || {},
|
|
408
|
+
context: persisted.context || {},
|
|
409
|
+
checkpoint: persisted.checkpoint || {},
|
|
410
|
+
startedAt: persisted.started_at || persisted.startedAt,
|
|
411
|
+
updatedAt: persisted.updated_at || persisted.updatedAt,
|
|
412
|
+
completedAt: persisted.completed_at || persisted.completedAt || null,
|
|
413
|
+
error: persisted.error || null,
|
|
414
|
+
summary: persisted.summary || null
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function persistDiskChatRun(runId, payload) {
|
|
419
|
+
const artifacts = getChatRunArtifacts(runId);
|
|
420
|
+
if (!artifacts) return payload;
|
|
421
|
+
writeJsonAtomic(artifacts.run_state_path, payload);
|
|
422
|
+
return payload;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function attachLegacyArtifactsToPersistedChatRun(persisted = {}) {
|
|
426
|
+
const runId = normalizeRunId(persisted.run_id || persisted.runId);
|
|
427
|
+
if (!runId) return persisted;
|
|
428
|
+
const snapshot = snapshotFromPersistedChatRun(persisted);
|
|
429
|
+
const result = buildLegacyChatResult(snapshot);
|
|
430
|
+
const artifacts = getChatRunArtifacts(runId);
|
|
431
|
+
const next = {
|
|
432
|
+
...persisted,
|
|
433
|
+
result,
|
|
434
|
+
resume: {
|
|
435
|
+
...(persisted.resume || {}),
|
|
436
|
+
checkpoint_path: result?.checkpoint_path || persisted.resume?.checkpoint_path || artifacts?.checkpoint_path || null,
|
|
437
|
+
output_csv: result?.output_csv || persisted.resume?.output_csv || artifacts?.output_csv || null
|
|
438
|
+
},
|
|
439
|
+
artifacts: artifacts || persisted.artifacts || null
|
|
440
|
+
};
|
|
441
|
+
return persistDiskChatRun(runId, next);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function finalizePersistedChatRun(persisted = {}, {
|
|
445
|
+
status = RUN_STATUS_FAILED,
|
|
446
|
+
error = null,
|
|
447
|
+
message = ""
|
|
448
|
+
} = {}) {
|
|
449
|
+
const runId = normalizeRunId(persisted.run_id || persisted.runId);
|
|
450
|
+
if (!runId) return persisted;
|
|
451
|
+
const now = new Date().toISOString();
|
|
452
|
+
const normalizedError = status === RUN_STATUS_FAILED
|
|
453
|
+
? {
|
|
454
|
+
name: error?.name || "Error",
|
|
455
|
+
code: error?.code || "STALE_RUN_PROCESS_EXITED",
|
|
456
|
+
message: error?.message || message || "Boss chat run process exited before it wrote a terminal state."
|
|
457
|
+
}
|
|
458
|
+
: null;
|
|
459
|
+
const next = {
|
|
460
|
+
...persisted,
|
|
461
|
+
run_id: runId,
|
|
462
|
+
state: status,
|
|
463
|
+
status,
|
|
464
|
+
stage: persisted.stage || persisted.phase || "chat:stale",
|
|
465
|
+
updated_at: now,
|
|
466
|
+
heartbeat_at: now,
|
|
467
|
+
completed_at: persisted.completed_at || now,
|
|
468
|
+
last_message: normalizedError?.message || message || status,
|
|
469
|
+
control: {
|
|
470
|
+
...(persisted.control || {}),
|
|
471
|
+
cancel_requested: false
|
|
472
|
+
},
|
|
473
|
+
error: normalizedError,
|
|
474
|
+
summary: persisted.summary || null
|
|
475
|
+
};
|
|
476
|
+
return attachLegacyArtifactsToPersistedChatRun(next);
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function persistedChatRunArtifactMissing(persisted = {}) {
|
|
480
|
+
const runId = normalizeRunId(persisted.run_id || persisted.runId);
|
|
481
|
+
const artifacts = getChatRunArtifacts(runId);
|
|
482
|
+
const outputCsv = persisted.result?.output_csv
|
|
483
|
+
|| persisted.resume?.output_csv
|
|
484
|
+
|| persisted.artifacts?.output_csv
|
|
485
|
+
|| artifacts?.output_csv;
|
|
486
|
+
const reportJson = persisted.result?.report_json
|
|
487
|
+
|| persisted.artifacts?.report_json
|
|
488
|
+
|| artifacts?.report_json;
|
|
489
|
+
return Boolean(
|
|
490
|
+
!outputCsv
|
|
491
|
+
|| !reportJson
|
|
492
|
+
|| !fs.existsSync(outputCsv)
|
|
493
|
+
|| !fs.existsSync(reportJson)
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function reconcilePersistedChatRun(persisted = {}, { cancelStale = false } = {}) {
|
|
498
|
+
const status = persisted.status || persisted.state;
|
|
499
|
+
if (STALE_PROCESS_STATUSES.has(status) && !isPidAlive(persisted.pid)) {
|
|
500
|
+
const shouldCancel = cancelStale || status === RUN_STATUS_CANCELING || persisted.control?.cancel_requested === true;
|
|
501
|
+
return {
|
|
502
|
+
run: finalizePersistedChatRun(persisted, {
|
|
503
|
+
status: shouldCancel ? RUN_STATUS_CANCELED : RUN_STATUS_FAILED,
|
|
504
|
+
error: shouldCancel ? null : {
|
|
505
|
+
code: "STALE_RUN_PROCESS_EXITED",
|
|
506
|
+
message: `Boss chat run process is no longer alive for pid=${persisted.pid || "unknown"}.`
|
|
507
|
+
},
|
|
508
|
+
message: shouldCancel
|
|
509
|
+
? "Boss chat run was canceled after its worker process was no longer active."
|
|
510
|
+
: `Boss chat run process is no longer alive for pid=${persisted.pid || "unknown"}.`
|
|
511
|
+
}),
|
|
512
|
+
stale_finalized: true
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
if (ARTIFACT_STATUSES.has(status) && persistedChatRunArtifactMissing(persisted)) {
|
|
516
|
+
return {
|
|
517
|
+
run: attachLegacyArtifactsToPersistedChatRun(persisted),
|
|
518
|
+
artifacts_repaired: true
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
return {
|
|
522
|
+
run: persisted
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
|
|
340
526
|
function buildLegacyChatResult(snapshot) {
|
|
341
527
|
if (!snapshot) return null;
|
|
342
528
|
const artifacts = ensureChatRunArtifacts(snapshot);
|
|
@@ -791,14 +977,32 @@ async function buildNeedInputResponse({ args, missingFields, normalized }) {
|
|
|
791
977
|
};
|
|
792
978
|
}
|
|
793
979
|
|
|
794
|
-
function shouldRequestChatResume(args = {}) {
|
|
795
|
-
|
|
980
|
+
function shouldRequestChatResume(args = {}, context = {}) {
|
|
981
|
+
const action = normalizeText(args.post_action || args.action).toLowerCase();
|
|
982
|
+
if (
|
|
983
|
+
args.request_cv === false
|
|
984
|
+
|| args.request_resume === false
|
|
985
|
+
|| args.ask_cv === false
|
|
986
|
+
|| args.execute_post_action === false
|
|
987
|
+
|| args.no_request_cv === true
|
|
988
|
+
|| args.no_request_resume === true
|
|
989
|
+
|| CHAT_DISABLE_REQUEST_RESUME_ACTIONS.has(action)
|
|
990
|
+
) {
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
if (
|
|
796
994
|
args.request_cv === true
|
|
797
995
|
|| args.request_resume === true
|
|
798
996
|
|| args.ask_cv === true
|
|
799
997
|
|| args.execute_post_action === true
|
|
800
|
-
||
|
|
801
|
-
)
|
|
998
|
+
|| CHAT_REQUEST_RESUME_ACTIONS.has(action)
|
|
999
|
+
) {
|
|
1000
|
+
return true;
|
|
1001
|
+
}
|
|
1002
|
+
if (typeof context.request_resume_for_passed === "boolean") {
|
|
1003
|
+
return context.request_resume_for_passed;
|
|
1004
|
+
}
|
|
1005
|
+
return true;
|
|
802
1006
|
}
|
|
803
1007
|
|
|
804
1008
|
function isDebugTestMode(args = {}) {
|
|
@@ -1300,12 +1504,15 @@ export function getBossChatRunTool({ args = {} } = {}) {
|
|
|
1300
1504
|
} catch {
|
|
1301
1505
|
const persisted = readChatRunState(runId);
|
|
1302
1506
|
if (persisted) {
|
|
1507
|
+
const reconciled = reconcilePersistedChatRun(persisted);
|
|
1303
1508
|
return {
|
|
1304
1509
|
status: "RUN_STATUS",
|
|
1305
|
-
run:
|
|
1510
|
+
run: reconciled.run,
|
|
1306
1511
|
persistence: {
|
|
1307
1512
|
source: "disk",
|
|
1308
|
-
active_control_available: false
|
|
1513
|
+
active_control_available: false,
|
|
1514
|
+
stale_finalized: reconciled.stale_finalized === true,
|
|
1515
|
+
artifacts_repaired: reconciled.artifacts_repaired === true
|
|
1309
1516
|
},
|
|
1310
1517
|
runtime_evaluate_used: false,
|
|
1311
1518
|
method_summary: {},
|
|
@@ -1354,9 +1561,10 @@ export function pauseBossChatRunTool({ args = {} } = {}) {
|
|
|
1354
1561
|
} catch {
|
|
1355
1562
|
const persisted = readChatRunState(runId);
|
|
1356
1563
|
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
1564
|
+
const reconciled = reconcilePersistedChatRun(persisted);
|
|
1357
1565
|
return {
|
|
1358
1566
|
status: "PAUSE_IGNORED",
|
|
1359
|
-
run:
|
|
1567
|
+
run: reconciled.run,
|
|
1360
1568
|
message: "目标任务已结束,无需暂停。",
|
|
1361
1569
|
runtime_evaluate_used: false,
|
|
1362
1570
|
method_summary: {},
|
|
@@ -1412,19 +1620,23 @@ export function resumeBossChatRunTool({ args = {} } = {}) {
|
|
|
1412
1620
|
} catch {
|
|
1413
1621
|
const persisted = readChatRunState(runId);
|
|
1414
1622
|
if (persisted) {
|
|
1623
|
+
const reconciled = reconcilePersistedChatRun(persisted);
|
|
1624
|
+
const reconciledStatus = reconciled.run?.status || reconciled.run?.state;
|
|
1415
1625
|
return {
|
|
1416
1626
|
status: "FAILED",
|
|
1417
1627
|
error: {
|
|
1418
|
-
code: TERMINAL_STATUSES.has(
|
|
1419
|
-
message: TERMINAL_STATUSES.has(
|
|
1628
|
+
code: TERMINAL_STATUSES.has(reconciledStatus) ? "RUN_ALREADY_TERMINATED" : "RUN_NOT_ACTIVE",
|
|
1629
|
+
message: TERMINAL_STATUSES.has(reconciledStatus)
|
|
1420
1630
|
? "目标任务已结束,无法继续。"
|
|
1421
1631
|
: "该 run 只有磁盘快照,没有当前进程内的活动 CDP 会话,无法安全继续。",
|
|
1422
|
-
retryable: !TERMINAL_STATUSES.has(
|
|
1632
|
+
retryable: !TERMINAL_STATUSES.has(reconciledStatus)
|
|
1423
1633
|
},
|
|
1424
|
-
run:
|
|
1634
|
+
run: reconciled.run,
|
|
1425
1635
|
persistence: {
|
|
1426
1636
|
source: "disk",
|
|
1427
|
-
active_control_available: false
|
|
1637
|
+
active_control_available: false,
|
|
1638
|
+
stale_finalized: reconciled.stale_finalized === true,
|
|
1639
|
+
artifacts_repaired: reconciled.artifacts_repaired === true
|
|
1428
1640
|
},
|
|
1429
1641
|
runtime_evaluate_used: false,
|
|
1430
1642
|
method_summary: {},
|
|
@@ -1458,9 +1670,10 @@ export function cancelBossChatRunTool({ args = {} } = {}) {
|
|
|
1458
1670
|
} catch {
|
|
1459
1671
|
const persisted = readChatRunState(runId);
|
|
1460
1672
|
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
1673
|
+
const reconciled = reconcilePersistedChatRun(persisted);
|
|
1461
1674
|
return {
|
|
1462
1675
|
status: "CANCEL_IGNORED",
|
|
1463
|
-
run:
|
|
1676
|
+
run: reconciled.run,
|
|
1464
1677
|
message: "目标任务已结束,无需取消。",
|
|
1465
1678
|
runtime_evaluate_used: false,
|
|
1466
1679
|
method_summary: {},
|
|
@@ -1468,6 +1681,26 @@ export function cancelBossChatRunTool({ args = {} } = {}) {
|
|
|
1468
1681
|
chrome: null
|
|
1469
1682
|
};
|
|
1470
1683
|
}
|
|
1684
|
+
if (persisted) {
|
|
1685
|
+
const reconciled = reconcilePersistedChatRun(persisted, { cancelStale: true });
|
|
1686
|
+
if (reconciled.stale_finalized) {
|
|
1687
|
+
return {
|
|
1688
|
+
status: "CANCEL_REQUESTED",
|
|
1689
|
+
run: reconciled.run,
|
|
1690
|
+
message: "该 run 的后台进程已经不在,已将磁盘状态安全标记为 canceled 并生成结果文件。",
|
|
1691
|
+
persistence: {
|
|
1692
|
+
source: "disk",
|
|
1693
|
+
active_control_available: false,
|
|
1694
|
+
stale_finalized: true,
|
|
1695
|
+
artifacts_repaired: reconciled.artifacts_repaired === true
|
|
1696
|
+
},
|
|
1697
|
+
runtime_evaluate_used: false,
|
|
1698
|
+
method_summary: {},
|
|
1699
|
+
method_log: [],
|
|
1700
|
+
chrome: null
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1471
1704
|
return getBossChatRunTool({ args });
|
|
1472
1705
|
}
|
|
1473
1706
|
}
|
package/src/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { createRequire } from "node:module";
|
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import {
|
|
9
9
|
assertNoForbiddenCdpCalls,
|
|
10
|
+
buildBossChromeLaunchArgs,
|
|
10
11
|
bringPageToFront,
|
|
11
12
|
connectToChromeTarget,
|
|
12
13
|
enableDomains,
|
|
@@ -1994,14 +1995,7 @@ async function launchChrome(options = {}) {
|
|
|
1994
1995
|
}
|
|
1995
1996
|
|
|
1996
1997
|
const userDataDir = getChromeUserDataDir(port);
|
|
1997
|
-
const args =
|
|
1998
|
-
`--remote-debugging-port=${port}`,
|
|
1999
|
-
`--user-data-dir=${userDataDir}`,
|
|
2000
|
-
"--no-first-run",
|
|
2001
|
-
"--no-default-browser-check",
|
|
2002
|
-
"--new-window",
|
|
2003
|
-
bossUrl
|
|
2004
|
-
];
|
|
1998
|
+
const args = buildBossChromeLaunchArgs({ port, userDataDir, url: bossUrl });
|
|
2005
1999
|
const child = spawn(chromePath, args, {
|
|
2006
2000
|
detached: true,
|
|
2007
2001
|
stdio: "ignore",
|
|
@@ -7,6 +7,12 @@ import CDP from "chrome-remote-interface";
|
|
|
7
7
|
export const DEFAULT_CHROME_HOST = "127.0.0.1";
|
|
8
8
|
export const DEFAULT_CHROME_PORT = 9222;
|
|
9
9
|
export const BOSS_LOGIN_URL = "https://www.zhipin.com/web/user/?ka=bticket";
|
|
10
|
+
export const LID_CLOSED_SAFE_CHROME_ARGS = [
|
|
11
|
+
"--disable-backgrounding-occluded-windows",
|
|
12
|
+
"--disable-background-timer-throttling",
|
|
13
|
+
"--disable-renderer-backgrounding",
|
|
14
|
+
"--disable-features=CalculateNativeWinOcclusion"
|
|
15
|
+
];
|
|
10
16
|
|
|
11
17
|
export const ALLOWED_CDP_DOMAINS = new Set([
|
|
12
18
|
"Accessibility",
|
|
@@ -208,6 +214,33 @@ export function getBossChromeUserDataDir(port = DEFAULT_CHROME_PORT) {
|
|
|
208
214
|
return sharedPath;
|
|
209
215
|
}
|
|
210
216
|
|
|
217
|
+
function parseExtraChromeArgs(value = "") {
|
|
218
|
+
return String(value || "")
|
|
219
|
+
.split(/\s+/)
|
|
220
|
+
.map((item) => item.trim())
|
|
221
|
+
.filter(Boolean);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function buildBossChromeLaunchArgs({
|
|
225
|
+
port = DEFAULT_CHROME_PORT,
|
|
226
|
+
userDataDir = "",
|
|
227
|
+
url = "about:blank",
|
|
228
|
+
extraArgs = []
|
|
229
|
+
} = {}) {
|
|
230
|
+
const args = [
|
|
231
|
+
`--remote-debugging-port=${port}`,
|
|
232
|
+
`--user-data-dir=${userDataDir}`,
|
|
233
|
+
"--no-first-run",
|
|
234
|
+
"--no-default-browser-check",
|
|
235
|
+
...LID_CLOSED_SAFE_CHROME_ARGS,
|
|
236
|
+
...parseExtraChromeArgs(process.env.BOSS_MCP_EXTRA_CHROME_ARGS),
|
|
237
|
+
...extraArgs,
|
|
238
|
+
"--new-window",
|
|
239
|
+
url
|
|
240
|
+
];
|
|
241
|
+
return Array.from(new Set(args.filter(Boolean)));
|
|
242
|
+
}
|
|
243
|
+
|
|
211
244
|
export async function waitForChromeDebugPort({
|
|
212
245
|
host = DEFAULT_CHROME_HOST,
|
|
213
246
|
port = DEFAULT_CHROME_PORT,
|
|
@@ -250,14 +283,7 @@ export async function launchChromeDebugInstance({
|
|
|
250
283
|
throw new Error("Chrome executable not found. Set BOSS_MCP_CHROME_PATH or BOSS_RECOMMEND_CHROME_PATH.");
|
|
251
284
|
}
|
|
252
285
|
const userDataDir = getBossChromeUserDataDir(port);
|
|
253
|
-
const args =
|
|
254
|
-
`--remote-debugging-port=${port}`,
|
|
255
|
-
`--user-data-dir=${userDataDir}`,
|
|
256
|
-
"--no-first-run",
|
|
257
|
-
"--no-default-browser-check",
|
|
258
|
-
"--new-window",
|
|
259
|
-
url
|
|
260
|
-
];
|
|
286
|
+
const args = buildBossChromeLaunchArgs({ port, userDataDir, url });
|
|
261
287
|
const child = spawn(chromePath, args, {
|
|
262
288
|
detached: true,
|
|
263
289
|
stdio: "ignore",
|
|
@@ -277,6 +303,7 @@ export async function launchChromeDebugInstance({
|
|
|
277
303
|
launched: true,
|
|
278
304
|
chrome_path: chromePath,
|
|
279
305
|
user_data_dir: userDataDir,
|
|
306
|
+
launch_args: args,
|
|
280
307
|
port,
|
|
281
308
|
url,
|
|
282
309
|
readiness: {
|