@reconcrap/boss-recommend-mcp 2.1.23 → 2.1.24
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 +5 -0
- package/bin/boss-recommend-mcp.js +4 -4
- package/package.json +6 -1
- package/scripts/install-macos.sh +280 -280
- package/scripts/postinstall.cjs +44 -44
- package/skills/boss-chat/README.md +43 -42
- package/skills/boss-chat/SKILL.md +107 -106
- package/skills/boss-recommend-pipeline/README.md +13 -13
- package/skills/boss-recommend-pipeline/SKILL.md +47 -47
- package/skills/boss-recruit-pipeline/README.md +19 -19
- package/skills/boss-recruit-pipeline/SKILL.md +89 -89
- package/src/chat-mcp.js +301 -127
- package/src/core/boss-cards/index.js +199 -199
- package/src/core/browser/index.js +286 -136
- package/src/core/capture/index.js +2930 -1201
- package/src/core/cv-acquisition/index.js +512 -238
- package/src/core/cv-capture-target/index.js +513 -299
- package/src/core/greet-quota/index.js +71 -71
- package/src/core/infinite-list/index.js +31 -31
- package/src/core/reporting/legacy-csv.js +12 -12
- package/src/core/run/detached-launcher.js +305 -0
- package/src/core/run/index.js +105 -52
- package/src/core/run/timing.js +33 -33
- package/src/core/run/windows-detached-worker.ps1 +106 -0
- package/src/core/screening/index.js +2135 -2135
- package/src/core/self-heal/index.js +989 -973
- package/src/core/self-heal/viewport.js +1505 -564
- package/src/detached-worker.js +99 -99
- package/src/domains/chat/action-journal.js +443 -0
- package/src/domains/chat/cards.js +137 -137
- package/src/domains/chat/constants.js +9 -9
- package/src/domains/chat/detail.js +1684 -401
- package/src/domains/chat/index.js +8 -7
- package/src/domains/chat/jobs.js +620 -620
- package/src/domains/chat/page-guard.js +157 -122
- package/src/domains/chat/roots.js +56 -56
- package/src/domains/chat/run-service.js +1801 -760
- package/src/domains/common/account-rights-panel.js +314 -314
- package/src/domains/common/recovery-settle.js +159 -159
- package/src/domains/recommend/actions.js +515 -472
- package/src/domains/recommend/cards.js +243 -243
- package/src/domains/recommend/colleague-contact.js +333 -333
- package/src/domains/recommend/constants.js +92 -92
- package/src/domains/recommend/detail.js +12 -12
- package/src/domains/recommend/filters.js +611 -611
- package/src/domains/recommend/index.js +9 -9
- package/src/domains/recommend/jobs.js +542 -542
- package/src/domains/recommend/location.js +736 -736
- package/src/domains/recommend/refresh.js +422 -422
- package/src/domains/recommend/roots.js +80 -80
- package/src/domains/recommend/run-service.js +1791 -1205
- package/src/domains/recommend/scopes.js +246 -246
- package/src/domains/recruit/actions.js +277 -277
- package/src/domains/recruit/cards.js +74 -74
- package/src/domains/recruit/constants.js +236 -236
- package/src/domains/recruit/detail.js +588 -588
- package/src/domains/recruit/index.js +9 -9
- package/src/domains/recruit/instruction-parser.js +866 -866
- package/src/domains/recruit/refresh.js +45 -45
- package/src/domains/recruit/roots.js +68 -68
- package/src/domains/recruit/run-service.js +1817 -1620
- package/src/domains/recruit/search.js +3229 -3229
- package/src/index.js +16 -1
- package/src/parser.js +1296 -1296
- package/src/recommend-mcp.js +551 -362
- package/src/recommend-scheduler.js +75 -75
package/src/recommend-mcp.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
|
-
import {
|
|
5
|
-
assertNoForbiddenCdpCalls,
|
|
6
|
-
bringPageToFront,
|
|
7
|
-
connectToChromeTargetOrOpen,
|
|
8
|
-
createBossLoginRequiredError,
|
|
9
|
-
detectBossLoginState,
|
|
10
|
-
enableDomains,
|
|
11
|
-
FORBIDDEN_CDP_METHODS,
|
|
12
|
-
getMainFrameUrl,
|
|
13
|
-
isBossLoginUrl,
|
|
14
|
-
waitForMainFrameUrl,
|
|
15
|
-
sleep
|
|
16
|
-
} from "./core/browser/index.js";
|
|
4
|
+
import {
|
|
5
|
+
assertNoForbiddenCdpCalls,
|
|
6
|
+
bringPageToFront,
|
|
7
|
+
connectToChromeTargetOrOpen,
|
|
8
|
+
createBossLoginRequiredError,
|
|
9
|
+
detectBossLoginState,
|
|
10
|
+
enableDomains,
|
|
11
|
+
FORBIDDEN_CDP_METHODS,
|
|
12
|
+
getMainFrameUrl,
|
|
13
|
+
isBossLoginUrl,
|
|
14
|
+
waitForMainFrameUrl,
|
|
15
|
+
sleep
|
|
16
|
+
} from "./core/browser/index.js";
|
|
17
17
|
import {
|
|
18
18
|
RUN_STATUS_CANCELING,
|
|
19
19
|
RUN_STATUS_CANCELED,
|
|
@@ -278,22 +278,22 @@ function normalizeScreeningModeArg(args = {}) {
|
|
|
278
278
|
: "llm";
|
|
279
279
|
}
|
|
280
280
|
|
|
281
|
-
function collectRecommendDebugTestOptions(args = {}, normalized = {}) {
|
|
282
|
-
const reasons = [];
|
|
281
|
+
function collectRecommendDebugTestOptions(args = {}, normalized = {}) {
|
|
282
|
+
const reasons = [];
|
|
283
283
|
if (normalizeScreeningModeArg(args) === "deterministic") reasons.push("deterministic_screening");
|
|
284
284
|
if (args.allow_card_only_screening === true) reasons.push("allow_card_only_screening");
|
|
285
285
|
if (parseNonNegativeInteger(args.detail_limit, null) === 0) reasons.push("detail_limit=0");
|
|
286
286
|
if (args.no_filter === true) reasons.push("no_filter");
|
|
287
|
-
if (args.filter_enabled === false) reasons.push("filter_enabled=false");
|
|
288
|
-
if (args.debug_force_list_end_after_processed != null) {
|
|
289
|
-
reasons.push("debug_force_list_end_after_processed");
|
|
290
|
-
}
|
|
291
|
-
if (args.debug_force_context_recovery_after_processed != null) {
|
|
292
|
-
reasons.push("debug_force_context_recovery_after_processed");
|
|
293
|
-
}
|
|
294
|
-
if (args.debug_force_cdp_reconnect_after_processed != null) {
|
|
295
|
-
reasons.push("debug_force_cdp_reconnect_after_processed");
|
|
296
|
-
}
|
|
287
|
+
if (args.filter_enabled === false) reasons.push("filter_enabled=false");
|
|
288
|
+
if (args.debug_force_list_end_after_processed != null) {
|
|
289
|
+
reasons.push("debug_force_list_end_after_processed");
|
|
290
|
+
}
|
|
291
|
+
if (args.debug_force_context_recovery_after_processed != null) {
|
|
292
|
+
reasons.push("debug_force_context_recovery_after_processed");
|
|
293
|
+
}
|
|
294
|
+
if (args.debug_force_cdp_reconnect_after_processed != null) {
|
|
295
|
+
reasons.push("debug_force_cdp_reconnect_after_processed");
|
|
296
|
+
}
|
|
297
297
|
if (args.dry_run_post_action === true) reasons.push("dry_run_post_action");
|
|
298
298
|
if (args.execute_post_action === false && normalized.postAction && normalized.postAction !== "none") {
|
|
299
299
|
reasons.push("execute_post_action=false");
|
|
@@ -313,36 +313,44 @@ function resolveRecommendDetailLimit(args = {}, normalized = {}) {
|
|
|
313
313
|
return requested;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
function methodSummary(methodLog = []) {
|
|
317
|
-
const summary = {};
|
|
318
|
-
for (const entry of methodLog || []) {
|
|
319
|
-
const method = compactCdpMethodName(entry?.method || entry || "");
|
|
320
|
-
if (!method) continue;
|
|
321
|
-
summary[method] = (summary[method] || 0) + 1;
|
|
322
|
-
}
|
|
323
|
-
return summary;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function compactCdpMethodName(value) {
|
|
327
|
-
const method = normalizeText(value);
|
|
328
|
-
return /^[A-Za-z][A-Za-z0-9_]*\.[A-Za-z][A-Za-z0-9_]*(?::retry_after_reconnect)?$/.test(method)
|
|
329
|
-
? method
|
|
330
|
-
: "";
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function compactCdpMethodTimestamp(value) {
|
|
334
|
-
const timestamp = normalizeText(value);
|
|
335
|
-
const parsed = Date.parse(timestamp);
|
|
336
|
-
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : "";
|
|
337
|
-
}
|
|
338
|
-
|
|
316
|
+
function methodSummary(methodLog = []) {
|
|
317
|
+
const summary = {};
|
|
318
|
+
for (const entry of methodLog || []) {
|
|
319
|
+
const method = compactCdpMethodName(entry?.method || entry || "");
|
|
320
|
+
if (!method) continue;
|
|
321
|
+
summary[method] = (summary[method] || 0) + 1;
|
|
322
|
+
}
|
|
323
|
+
return summary;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function compactCdpMethodName(value) {
|
|
327
|
+
const method = normalizeText(value);
|
|
328
|
+
return /^[A-Za-z][A-Za-z0-9_]*\.[A-Za-z][A-Za-z0-9_]*(?::retry_after_reconnect)?$/.test(method)
|
|
329
|
+
? method
|
|
330
|
+
: "";
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function compactCdpMethodTimestamp(value) {
|
|
334
|
+
const timestamp = normalizeText(value);
|
|
335
|
+
const parsed = Date.parse(timestamp);
|
|
336
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : "";
|
|
337
|
+
}
|
|
338
|
+
|
|
339
339
|
function compactMethodLogForStatus(methodLog = []) {
|
|
340
340
|
if (!Array.isArray(methodLog)) return [];
|
|
341
341
|
return methodLog
|
|
342
|
-
.map((entry) =>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
342
|
+
.map((entry) => {
|
|
343
|
+
const compact = {
|
|
344
|
+
method: compactCdpMethodName(entry?.method || entry || ""),
|
|
345
|
+
at: compactCdpMethodTimestamp(entry?.at || "")
|
|
346
|
+
};
|
|
347
|
+
for (const key of ["connection_epoch", "replay_of_connection_epoch"]) {
|
|
348
|
+
if (Number.isInteger(entry?.[key]) && entry[key] >= 0) compact[key] = entry[key];
|
|
349
|
+
}
|
|
350
|
+
const replayPolicy = normalizeText(entry?.replay_policy || "");
|
|
351
|
+
if (replayPolicy) compact.replay_policy = replayPolicy.slice(0, 100);
|
|
352
|
+
return compact;
|
|
353
|
+
})
|
|
346
354
|
.filter((entry) => Boolean(entry.method))
|
|
347
355
|
.slice(-STATUS_METHOD_LOG_TAIL_LIMIT);
|
|
348
356
|
}
|
|
@@ -359,130 +367,130 @@ function plainRecord(value) {
|
|
|
359
367
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
360
368
|
}
|
|
361
369
|
|
|
362
|
-
function nonEmptyRecord(value) {
|
|
363
|
-
const record = plainRecord(value);
|
|
364
|
-
return Object.keys(record).length ? record : null;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
function compactMethodSummaryForStatus(value = {}) {
|
|
368
|
-
const compact = {};
|
|
369
|
-
for (const [rawMethod, rawCount] of Object.entries(plainRecord(value))) {
|
|
370
|
-
const method = compactCdpMethodName(rawMethod);
|
|
371
|
-
const count = Number(rawCount);
|
|
372
|
-
if (!method || !Number.isInteger(count) || count < 1) continue;
|
|
373
|
-
compact[method] = count;
|
|
374
|
-
}
|
|
375
|
-
return compact;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function compactChromeEvidenceUrl(value) {
|
|
379
|
-
const text = normalizeText(value);
|
|
380
|
-
if (!text) return null;
|
|
381
|
-
try {
|
|
382
|
-
const parsed = new URL(text);
|
|
383
|
-
parsed.username = "";
|
|
384
|
-
parsed.password = "";
|
|
385
|
-
parsed.search = "";
|
|
386
|
-
parsed.hash = "";
|
|
387
|
-
return parsed.toString();
|
|
388
|
-
} catch {
|
|
389
|
-
return text.split(/[?#]/, 1)[0] || null;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
function compactChromeAutoLaunchEvidence(value = {}) {
|
|
394
|
-
const source = plainRecord(value);
|
|
395
|
-
if (!Object.keys(source).length) return null;
|
|
396
|
-
const compact = {};
|
|
397
|
-
const booleanKeys = [
|
|
398
|
-
"launched",
|
|
399
|
-
"reused",
|
|
400
|
-
"guard_checked",
|
|
401
|
-
"required_flags_ok",
|
|
402
|
-
"replaced",
|
|
403
|
-
"target_created",
|
|
404
|
-
"fallback_target",
|
|
405
|
-
"fallback_any_page"
|
|
406
|
-
];
|
|
407
|
-
for (const key of booleanKeys) {
|
|
408
|
-
if (typeof source[key] === "boolean") compact[key] = source[key];
|
|
409
|
-
}
|
|
410
|
-
for (const key of ["port", "target_count", "command_line_args_count"]) {
|
|
411
|
-
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
412
|
-
}
|
|
413
|
-
for (const key of ["close_method", "command_line_source"]) {
|
|
414
|
-
const text = normalizeText(source[key]);
|
|
415
|
-
if (text) compact[key] = text;
|
|
416
|
-
}
|
|
417
|
-
return Object.keys(compact).length ? compact : null;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
function compactChromeEvidence(value = {}) {
|
|
421
|
-
const source = plainRecord(value);
|
|
422
|
-
if (!Object.keys(source).length) return null;
|
|
423
|
-
const compact = {};
|
|
424
|
-
const host = normalizeText(source.host);
|
|
425
|
-
const targetId = normalizeText(source.target_id);
|
|
426
|
-
const targetUrl = compactChromeEvidenceUrl(source.target_url);
|
|
427
|
-
if (host) compact.host = host;
|
|
428
|
-
if (Number.isInteger(source.port) && source.port > 0) compact.port = source.port;
|
|
429
|
-
if (targetUrl) compact.target_url = targetUrl;
|
|
430
|
-
if (targetId) compact.target_id = targetId;
|
|
431
|
-
const autoLaunch = compactChromeAutoLaunchEvidence(source.auto_launch);
|
|
432
|
-
if (autoLaunch) compact.auto_launch = autoLaunch;
|
|
433
|
-
return Object.keys(compact).length ? compact : null;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
function methodEvidenceFlags(methodSummaryValue = {}) {
|
|
437
|
-
const methods = Object.keys(methodSummaryValue);
|
|
438
|
-
return {
|
|
439
|
-
runtime_evaluate_used: methods.some((method) => method.split(".", 1)[0] === "Runtime"),
|
|
440
|
-
script_injection_used: methods.some((method) => (
|
|
441
|
-
FORBIDDEN_CDP_METHODS.has(method.replace(/:retry_after_reconnect$/, ""))
|
|
442
|
-
))
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
function buildPersistedCdpEvidence({ meta = {}, persisted = {} } = {}) {
|
|
447
|
-
const hasLiveMethodLog = Array.isArray(meta.methodLog);
|
|
448
|
-
const persistedMethodLog = compactMethodLogForStatus(persisted.method_log);
|
|
449
|
-
const methodLog = hasLiveMethodLog
|
|
450
|
-
? compactMethodLogForStatus(meta.methodLog)
|
|
451
|
-
: persistedMethodLog;
|
|
452
|
-
const persistedSummary = compactMethodSummaryForStatus(persisted.method_summary);
|
|
453
|
-
const summary = hasLiveMethodLog
|
|
454
|
-
? methodSummary(meta.methodLog)
|
|
455
|
-
: Object.keys(persistedSummary).length
|
|
456
|
-
? persistedSummary
|
|
457
|
-
: methodSummary(methodLog);
|
|
458
|
-
const liveTotal = hasLiveMethodLog ? meta.methodLog.length : null;
|
|
459
|
-
const persistedTotal = Number(persisted.method_log_total);
|
|
460
|
-
const methodLogTotal = Number.isInteger(liveTotal)
|
|
461
|
-
? liveTotal
|
|
462
|
-
: Number.isInteger(persistedTotal) && persistedTotal >= methodLog.length
|
|
463
|
-
? persistedTotal
|
|
464
|
-
: methodLog.length;
|
|
465
|
-
const inferredFlags = methodEvidenceFlags(summary);
|
|
466
|
-
return {
|
|
467
|
-
runtime_evaluate_used: hasLiveMethodLog
|
|
468
|
-
? inferredFlags.runtime_evaluate_used
|
|
469
|
-
: persisted.runtime_evaluate_used === true || inferredFlags.runtime_evaluate_used,
|
|
470
|
-
script_injection_used: hasLiveMethodLog
|
|
471
|
-
? inferredFlags.script_injection_used
|
|
472
|
-
: persisted.script_injection_used === true || inferredFlags.script_injection_used,
|
|
473
|
-
method_summary: summary,
|
|
474
|
-
method_log: methodLog,
|
|
475
|
-
method_log_total: methodLogTotal,
|
|
476
|
-
chrome: compactChromeEvidence(meta.chrome || persisted.chrome)
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function attachPersistedCdpEvidence(payload, persisted = {}) {
|
|
481
|
-
return {
|
|
482
|
-
...payload,
|
|
483
|
-
...buildPersistedCdpEvidence({ persisted })
|
|
484
|
-
};
|
|
485
|
-
}
|
|
370
|
+
function nonEmptyRecord(value) {
|
|
371
|
+
const record = plainRecord(value);
|
|
372
|
+
return Object.keys(record).length ? record : null;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function compactMethodSummaryForStatus(value = {}) {
|
|
376
|
+
const compact = {};
|
|
377
|
+
for (const [rawMethod, rawCount] of Object.entries(plainRecord(value))) {
|
|
378
|
+
const method = compactCdpMethodName(rawMethod);
|
|
379
|
+
const count = Number(rawCount);
|
|
380
|
+
if (!method || !Number.isInteger(count) || count < 1) continue;
|
|
381
|
+
compact[method] = count;
|
|
382
|
+
}
|
|
383
|
+
return compact;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function compactChromeEvidenceUrl(value) {
|
|
387
|
+
const text = normalizeText(value);
|
|
388
|
+
if (!text) return null;
|
|
389
|
+
try {
|
|
390
|
+
const parsed = new URL(text);
|
|
391
|
+
parsed.username = "";
|
|
392
|
+
parsed.password = "";
|
|
393
|
+
parsed.search = "";
|
|
394
|
+
parsed.hash = "";
|
|
395
|
+
return parsed.toString();
|
|
396
|
+
} catch {
|
|
397
|
+
return text.split(/[?#]/, 1)[0] || null;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function compactChromeAutoLaunchEvidence(value = {}) {
|
|
402
|
+
const source = plainRecord(value);
|
|
403
|
+
if (!Object.keys(source).length) return null;
|
|
404
|
+
const compact = {};
|
|
405
|
+
const booleanKeys = [
|
|
406
|
+
"launched",
|
|
407
|
+
"reused",
|
|
408
|
+
"guard_checked",
|
|
409
|
+
"required_flags_ok",
|
|
410
|
+
"replaced",
|
|
411
|
+
"target_created",
|
|
412
|
+
"fallback_target",
|
|
413
|
+
"fallback_any_page"
|
|
414
|
+
];
|
|
415
|
+
for (const key of booleanKeys) {
|
|
416
|
+
if (typeof source[key] === "boolean") compact[key] = source[key];
|
|
417
|
+
}
|
|
418
|
+
for (const key of ["port", "target_count", "command_line_args_count"]) {
|
|
419
|
+
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
420
|
+
}
|
|
421
|
+
for (const key of ["close_method", "command_line_source"]) {
|
|
422
|
+
const text = normalizeText(source[key]);
|
|
423
|
+
if (text) compact[key] = text;
|
|
424
|
+
}
|
|
425
|
+
return Object.keys(compact).length ? compact : null;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function compactChromeEvidence(value = {}) {
|
|
429
|
+
const source = plainRecord(value);
|
|
430
|
+
if (!Object.keys(source).length) return null;
|
|
431
|
+
const compact = {};
|
|
432
|
+
const host = normalizeText(source.host);
|
|
433
|
+
const targetId = normalizeText(source.target_id);
|
|
434
|
+
const targetUrl = compactChromeEvidenceUrl(source.target_url);
|
|
435
|
+
if (host) compact.host = host;
|
|
436
|
+
if (Number.isInteger(source.port) && source.port > 0) compact.port = source.port;
|
|
437
|
+
if (targetUrl) compact.target_url = targetUrl;
|
|
438
|
+
if (targetId) compact.target_id = targetId;
|
|
439
|
+
const autoLaunch = compactChromeAutoLaunchEvidence(source.auto_launch);
|
|
440
|
+
if (autoLaunch) compact.auto_launch = autoLaunch;
|
|
441
|
+
return Object.keys(compact).length ? compact : null;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
function methodEvidenceFlags(methodSummaryValue = {}) {
|
|
445
|
+
const methods = Object.keys(methodSummaryValue);
|
|
446
|
+
return {
|
|
447
|
+
runtime_evaluate_used: methods.some((method) => method.split(".", 1)[0] === "Runtime"),
|
|
448
|
+
script_injection_used: methods.some((method) => (
|
|
449
|
+
FORBIDDEN_CDP_METHODS.has(method.replace(/:retry_after_reconnect$/, ""))
|
|
450
|
+
))
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function buildPersistedCdpEvidence({ meta = {}, persisted = {} } = {}) {
|
|
455
|
+
const hasLiveMethodLog = Array.isArray(meta.methodLog);
|
|
456
|
+
const persistedMethodLog = compactMethodLogForStatus(persisted.method_log);
|
|
457
|
+
const methodLog = hasLiveMethodLog
|
|
458
|
+
? compactMethodLogForStatus(meta.methodLog)
|
|
459
|
+
: persistedMethodLog;
|
|
460
|
+
const persistedSummary = compactMethodSummaryForStatus(persisted.method_summary);
|
|
461
|
+
const summary = hasLiveMethodLog
|
|
462
|
+
? methodSummary(meta.methodLog)
|
|
463
|
+
: Object.keys(persistedSummary).length
|
|
464
|
+
? persistedSummary
|
|
465
|
+
: methodSummary(methodLog);
|
|
466
|
+
const liveTotal = hasLiveMethodLog ? meta.methodLog.length : null;
|
|
467
|
+
const persistedTotal = Number(persisted.method_log_total);
|
|
468
|
+
const methodLogTotal = Number.isInteger(liveTotal)
|
|
469
|
+
? liveTotal
|
|
470
|
+
: Number.isInteger(persistedTotal) && persistedTotal >= methodLog.length
|
|
471
|
+
? persistedTotal
|
|
472
|
+
: methodLog.length;
|
|
473
|
+
const inferredFlags = methodEvidenceFlags(summary);
|
|
474
|
+
return {
|
|
475
|
+
runtime_evaluate_used: hasLiveMethodLog
|
|
476
|
+
? inferredFlags.runtime_evaluate_used
|
|
477
|
+
: persisted.runtime_evaluate_used === true || inferredFlags.runtime_evaluate_used,
|
|
478
|
+
script_injection_used: hasLiveMethodLog
|
|
479
|
+
? inferredFlags.script_injection_used
|
|
480
|
+
: persisted.script_injection_used === true || inferredFlags.script_injection_used,
|
|
481
|
+
method_summary: summary,
|
|
482
|
+
method_log: methodLog,
|
|
483
|
+
method_log_total: methodLogTotal,
|
|
484
|
+
chrome: compactChromeEvidence(meta.chrome || persisted.chrome)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function attachPersistedCdpEvidence(payload, persisted = {}) {
|
|
489
|
+
return {
|
|
490
|
+
...payload,
|
|
491
|
+
...buildPersistedCdpEvidence({ persisted })
|
|
492
|
+
};
|
|
493
|
+
}
|
|
486
494
|
|
|
487
495
|
function normalizeRunId(runId) {
|
|
488
496
|
const normalized = normalizeText(runId);
|
|
@@ -530,12 +538,12 @@ function readJsonFile(filePath) {
|
|
|
530
538
|
|
|
531
539
|
function recommendSearchParamsForCsv(searchParams = {}) {
|
|
532
540
|
return {
|
|
533
|
-
school_tag: Object.prototype.hasOwnProperty.call(searchParams, "school_tag") ? searchParams.school_tag : "不限",
|
|
534
|
-
degree: Object.prototype.hasOwnProperty.call(searchParams, "degree") ? searchParams.degree : "不限",
|
|
535
|
-
gender: Object.prototype.hasOwnProperty.call(searchParams, "gender") ? searchParams.gender : "不限",
|
|
536
|
-
recent_not_view: Object.prototype.hasOwnProperty.call(searchParams, "recent_not_view") ? searchParams.recent_not_view : "不限",
|
|
537
|
-
current_city_only: Object.prototype.hasOwnProperty.call(searchParams, "current_city_only") ? searchParams.current_city_only : false,
|
|
538
|
-
activity_level: Object.prototype.hasOwnProperty.call(searchParams, "activity_level") ? searchParams.activity_level : "不限"
|
|
541
|
+
school_tag: Object.prototype.hasOwnProperty.call(searchParams, "school_tag") ? searchParams.school_tag : "不限",
|
|
542
|
+
degree: Object.prototype.hasOwnProperty.call(searchParams, "degree") ? searchParams.degree : "不限",
|
|
543
|
+
gender: Object.prototype.hasOwnProperty.call(searchParams, "gender") ? searchParams.gender : "不限",
|
|
544
|
+
recent_not_view: Object.prototype.hasOwnProperty.call(searchParams, "recent_not_view") ? searchParams.recent_not_view : "不限",
|
|
545
|
+
current_city_only: Object.prototype.hasOwnProperty.call(searchParams, "current_city_only") ? searchParams.current_city_only : false,
|
|
546
|
+
activity_level: Object.prototype.hasOwnProperty.call(searchParams, "activity_level") ? searchParams.activity_level : "不限"
|
|
539
547
|
};
|
|
540
548
|
}
|
|
541
549
|
|
|
@@ -574,12 +582,12 @@ function selectedRecommendJobForCsv(meta = {}, snapshot = {}) {
|
|
|
574
582
|
function buildRecommendCsvInputRows(snapshot = {}, meta = {}) {
|
|
575
583
|
const { context, confirmation, overrides, followUp, shared } = getSnapshotRequestContext(snapshot);
|
|
576
584
|
const searchParams = recommendSearchParamsForCsv(meta.parsed?.searchParams || {
|
|
577
|
-
school_tag: overrides.school_tag ?? confirmation.school_tag_value,
|
|
578
|
-
degree: overrides.degree ?? confirmation.degree_value,
|
|
579
|
-
gender: overrides.gender ?? confirmation.gender_value,
|
|
580
|
-
recent_not_view: overrides.recent_not_view ?? confirmation.recent_not_view_value,
|
|
581
|
-
current_city_only: overrides.current_city_only ?? false,
|
|
582
|
-
activity_level: overrides.activity_level ?? "不限"
|
|
585
|
+
school_tag: overrides.school_tag ?? confirmation.school_tag_value,
|
|
586
|
+
degree: overrides.degree ?? confirmation.degree_value,
|
|
587
|
+
gender: overrides.gender ?? confirmation.gender_value,
|
|
588
|
+
recent_not_view: overrides.recent_not_view ?? confirmation.recent_not_view_value,
|
|
589
|
+
current_city_only: overrides.current_city_only ?? false,
|
|
590
|
+
activity_level: overrides.activity_level ?? "不限"
|
|
583
591
|
});
|
|
584
592
|
const parsedScreenParams = meta.parsed?.screenParams || {};
|
|
585
593
|
const screenParams = {
|
|
@@ -654,26 +662,36 @@ function normalizeLegacyProgress(progress = {}, summary = null) {
|
|
|
654
662
|
: Number.isInteger(summary?.passed)
|
|
655
663
|
? summary.passed
|
|
656
664
|
: 0;
|
|
657
|
-
const normalized = {
|
|
658
|
-
...progress,
|
|
665
|
+
const normalized = {
|
|
666
|
+
...progress,
|
|
659
667
|
processed,
|
|
660
668
|
inspected: processed,
|
|
661
669
|
screened,
|
|
662
670
|
passed,
|
|
663
671
|
skipped: Number.isInteger(progress.skipped) ? progress.skipped : Math.max(processed - passed, 0),
|
|
664
|
-
greet_count: Number.isInteger(progress.greet_count) ? progress.greet_count : 0,
|
|
665
|
-
post_action_clicked: Number.isInteger(progress.post_action_clicked) ? progress.post_action_clicked : 0
|
|
666
|
-
};
|
|
667
|
-
if (Object.prototype.hasOwnProperty.call(normalized, "last_list_read_stale_diagnostic")) {
|
|
668
|
-
normalized.last_list_read_stale_diagnostic = compactListReadStaleDiagnosticForStatus(
|
|
669
|
-
normalized.last_list_read_stale_diagnostic
|
|
670
|
-
);
|
|
671
|
-
}
|
|
672
|
+
greet_count: Number.isInteger(progress.greet_count) ? progress.greet_count : 0,
|
|
673
|
+
post_action_clicked: Number.isInteger(progress.post_action_clicked) ? progress.post_action_clicked : 0
|
|
674
|
+
};
|
|
675
|
+
if (Object.prototype.hasOwnProperty.call(normalized, "last_list_read_stale_diagnostic")) {
|
|
676
|
+
normalized.last_list_read_stale_diagnostic = compactListReadStaleDiagnosticForStatus(
|
|
677
|
+
normalized.last_list_read_stale_diagnostic
|
|
678
|
+
);
|
|
679
|
+
}
|
|
672
680
|
if (Object.prototype.hasOwnProperty.call(normalized, "list_read_stale_diagnostics")) {
|
|
673
681
|
normalized.list_read_stale_diagnostics = compactListReadStaleDiagnosticsForStatus(
|
|
674
682
|
normalized.list_read_stale_diagnostics
|
|
675
683
|
);
|
|
676
684
|
}
|
|
685
|
+
if (Object.prototype.hasOwnProperty.call(normalized, "dom_stale_forensic")) {
|
|
686
|
+
normalized.dom_stale_forensic = compactDomStaleForensicForStatus(
|
|
687
|
+
normalized.dom_stale_forensic
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
if (Object.prototype.hasOwnProperty.call(normalized, "dom_stale_forensics")) {
|
|
691
|
+
normalized.dom_stale_forensics = compactDomStaleForensicsForStatus(
|
|
692
|
+
normalized.dom_stale_forensics
|
|
693
|
+
);
|
|
694
|
+
}
|
|
677
695
|
return normalized;
|
|
678
696
|
}
|
|
679
697
|
|
|
@@ -703,73 +721,236 @@ function compactPositiveInteger(value, fallback = null) {
|
|
|
703
721
|
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
704
722
|
}
|
|
705
723
|
|
|
706
|
-
function compactSmallRecord(value, fallback = null) {
|
|
724
|
+
function compactSmallRecord(value, fallback = null) {
|
|
707
725
|
const record = plainRecord(value);
|
|
708
726
|
if (!Object.keys(record).length) return fallback;
|
|
709
|
-
return clonePlain(record, fallback);
|
|
710
|
-
}
|
|
711
|
-
|
|
727
|
+
return clonePlain(record, fallback);
|
|
728
|
+
}
|
|
729
|
+
|
|
712
730
|
function compactListReadStaleDiagnosticForStatus(value) {
|
|
713
731
|
const source = plainRecord(value);
|
|
714
732
|
if (!Object.keys(source).length) return null;
|
|
715
733
|
const compact = {};
|
|
716
|
-
for (const key of [
|
|
734
|
+
for (const key of [
|
|
735
|
+
"name",
|
|
736
|
+
"code",
|
|
737
|
+
"message",
|
|
738
|
+
"phase",
|
|
739
|
+
"cdp_method",
|
|
740
|
+
"cdp_at",
|
|
741
|
+
"cdp_search_id",
|
|
742
|
+
"cdp_replay_policy",
|
|
743
|
+
"recovery_mode"
|
|
744
|
+
]) {
|
|
717
745
|
const text = normalizeText(source[key] || "");
|
|
718
746
|
if (text) compact[key] = text.slice(0, key === "message" ? 500 : 200);
|
|
719
747
|
}
|
|
720
|
-
for (const key of [
|
|
748
|
+
for (const key of [
|
|
749
|
+
"cdp_node_id",
|
|
750
|
+
"cdp_backend_node_id",
|
|
751
|
+
"cdp_connection_epoch",
|
|
752
|
+
"cdp_reconnected_epoch",
|
|
753
|
+
"attempt"
|
|
754
|
+
]) {
|
|
721
755
|
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
722
756
|
}
|
|
723
|
-
for (const key of [
|
|
757
|
+
for (const key of [
|
|
758
|
+
"exhausted",
|
|
759
|
+
"recovery_applied",
|
|
760
|
+
"recovered",
|
|
761
|
+
"cdp_replay_suppressed",
|
|
762
|
+
"cdp_outcome_unknown",
|
|
763
|
+
"cdp_reconnected",
|
|
764
|
+
"cdp_replayed_after_reconnect"
|
|
765
|
+
]) {
|
|
724
766
|
if (typeof source[key] === "boolean") compact[key] = source[key];
|
|
725
767
|
}
|
|
726
|
-
for (const key of ["at", "recovery_applied_at", "recovered_at"]) {
|
|
727
|
-
const text = normalizeText(source[key] || "");
|
|
728
|
-
if (text && Number.isFinite(Date.parse(text))) compact[key] = new Date(text).toISOString();
|
|
729
|
-
}
|
|
768
|
+
for (const key of ["at", "recovery_applied_at", "recovered_at"]) {
|
|
769
|
+
const text = normalizeText(source[key] || "");
|
|
770
|
+
if (text && Number.isFinite(Date.parse(text))) compact[key] = new Date(text).toISOString();
|
|
771
|
+
}
|
|
730
772
|
if (Array.isArray(source.cdp_param_keys)) {
|
|
731
|
-
compact.cdp_param_keys = source.cdp_param_keys
|
|
732
|
-
.map((key) => normalizeText(key))
|
|
773
|
+
compact.cdp_param_keys = source.cdp_param_keys
|
|
774
|
+
.map((key) => normalizeText(key))
|
|
733
775
|
.filter((key) => /^[A-Za-z][A-Za-z0-9_]*$/.test(key))
|
|
734
776
|
.slice(0, 20);
|
|
735
777
|
}
|
|
778
|
+
if (source.cdp_reconnect_error !== undefined && source.cdp_reconnect_error !== null) {
|
|
779
|
+
const reconnectError = plainRecord(source.cdp_reconnect_error);
|
|
780
|
+
if (Object.keys(reconnectError).length) {
|
|
781
|
+
const safeReconnectError = {};
|
|
782
|
+
for (const key of ["name", "code", "message"]) {
|
|
783
|
+
const text = normalizeText(reconnectError[key] || "");
|
|
784
|
+
if (text) safeReconnectError[key] = text.slice(0, key === "message" ? 500 : 200);
|
|
785
|
+
}
|
|
786
|
+
if (Object.keys(safeReconnectError).length) compact.cdp_reconnect_error = safeReconnectError;
|
|
787
|
+
} else {
|
|
788
|
+
const reconnectErrorText = normalizeText(source.cdp_reconnect_error);
|
|
789
|
+
if (reconnectErrorText) compact.cdp_reconnect_error = reconnectErrorText.slice(0, 500);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
736
792
|
return Object.keys(compact).length ? compact : null;
|
|
737
793
|
}
|
|
738
794
|
|
|
739
|
-
function
|
|
795
|
+
function compactDomStaleRootIdentityForStatus(value) {
|
|
796
|
+
const source = plainRecord(value);
|
|
797
|
+
if (!Object.keys(source).length) return null;
|
|
798
|
+
const compact = {};
|
|
799
|
+
for (const key of [
|
|
800
|
+
"connection_epoch",
|
|
801
|
+
"top_document_node_id",
|
|
802
|
+
"iframe_owner_node_id",
|
|
803
|
+
"iframe_document_node_id"
|
|
804
|
+
]) {
|
|
805
|
+
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
806
|
+
}
|
|
807
|
+
const iframeSelector = normalizeText(source.iframe_selector || "");
|
|
808
|
+
if (iframeSelector) compact.iframe_selector = iframeSelector.slice(0, 300);
|
|
809
|
+
return Object.keys(compact).length ? compact : null;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function compactDomStaleNumericRecordForStatus(value) {
|
|
813
|
+
const source = plainRecord(value);
|
|
814
|
+
if (!Object.keys(source).length) return null;
|
|
815
|
+
const compact = {};
|
|
816
|
+
for (const [key, rawValue] of Object.entries(source)) {
|
|
817
|
+
if (!/^[a-z][a-z0-9_]*$/i.test(key)) continue;
|
|
818
|
+
if (!Number.isInteger(rawValue) || rawValue < 0) continue;
|
|
819
|
+
compact[key] = rawValue;
|
|
820
|
+
if (Object.keys(compact).length >= 30) break;
|
|
821
|
+
}
|
|
822
|
+
return Object.keys(compact).length ? compact : null;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
function compactDomStaleLifecycleTimelineForStatus(value) {
|
|
740
826
|
if (!Array.isArray(value)) return [];
|
|
741
827
|
return value
|
|
742
|
-
.map((
|
|
828
|
+
.map((rawEntry) => {
|
|
829
|
+
const entry = plainRecord(rawEntry);
|
|
830
|
+
const compact = {};
|
|
831
|
+
const at = compactCdpMethodTimestamp(entry.at || "");
|
|
832
|
+
if (at) compact.at = at;
|
|
833
|
+
for (const key of ["type", "operation", "frame_id", "parent_frame_id", "loader_id"]) {
|
|
834
|
+
const text = normalizeText(entry[key] || "");
|
|
835
|
+
if (text) compact[key] = text.slice(0, 300);
|
|
836
|
+
}
|
|
837
|
+
if (Number.isInteger(entry.connection_epoch) && entry.connection_epoch >= 0) {
|
|
838
|
+
compact.connection_epoch = entry.connection_epoch;
|
|
839
|
+
}
|
|
840
|
+
const url = compactChromeEvidenceUrl(entry.url);
|
|
841
|
+
if (url) compact.url = url;
|
|
842
|
+
return Object.keys(compact).length ? compact : null;
|
|
843
|
+
})
|
|
743
844
|
.filter(Boolean)
|
|
744
|
-
.slice(-
|
|
845
|
+
.slice(-20);
|
|
745
846
|
}
|
|
746
847
|
|
|
747
|
-
function
|
|
848
|
+
function compactDomStaleCandidateForStatus(value) {
|
|
748
849
|
const source = plainRecord(value);
|
|
749
850
|
if (!Object.keys(source).length) return null;
|
|
750
851
|
const compact = {};
|
|
751
|
-
const
|
|
752
|
-
if (diagnostic) compact.diagnostic = diagnostic;
|
|
753
|
-
const recentDiagnostics = compactListReadStaleDiagnosticsForStatus(source.recent_diagnostics);
|
|
754
|
-
if (recentDiagnostics.length) compact.recent_diagnostics = recentDiagnostics;
|
|
755
|
-
for (const key of ["recovery_count", "recovery_applied_count"]) {
|
|
852
|
+
for (const key of ["index", "card_node_id", "visible_index", "failing_list_node_id"]) {
|
|
756
853
|
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
757
854
|
}
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
855
|
+
const candidateKey = normalizeText(source.key || "");
|
|
856
|
+
if (candidateKey) compact.key = candidateKey.slice(0, 300);
|
|
857
|
+
return Object.keys(compact).length ? compact : null;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function compactDomStaleRecoveryForStatus(value) {
|
|
861
|
+
const source = plainRecord(value);
|
|
862
|
+
if (!Object.keys(source).length) return null;
|
|
863
|
+
const compact = {};
|
|
864
|
+
for (const key of ["status", "mode", "escalated_from", "method"]) {
|
|
865
|
+
const text = normalizeText(source[key] || "");
|
|
866
|
+
if (text) compact[key] = text.slice(0, 200);
|
|
761
867
|
}
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
868
|
+
const at = compactCdpMethodTimestamp(source.at || "");
|
|
869
|
+
if (at) compact.at = at;
|
|
870
|
+
if (typeof source.ok === "boolean") compact.ok = source.ok;
|
|
871
|
+
if (Number.isInteger(source.card_count) && source.card_count >= 0) {
|
|
872
|
+
compact.card_count = source.card_count;
|
|
873
|
+
}
|
|
874
|
+
const error = compactListReadStaleDiagnosticForStatus(source.error);
|
|
875
|
+
if (error) compact.error = error;
|
|
876
|
+
return Object.keys(compact).length ? compact : null;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
function compactDomStaleForensicForStatus(value) {
|
|
880
|
+
const source = plainRecord(value);
|
|
881
|
+
if (!Object.keys(source).length) return null;
|
|
882
|
+
const compact = {};
|
|
883
|
+
if (Number.isInteger(source.schema_version) && source.schema_version >= 0) {
|
|
884
|
+
compact.schema_version = source.schema_version;
|
|
885
|
+
}
|
|
886
|
+
for (const key of ["event_id", "event_type", "phase", "operation", "detail_step"]) {
|
|
887
|
+
const text = normalizeText(source[key] || "");
|
|
888
|
+
if (text) compact[key] = text.slice(0, key === "event_id" ? 300 : 200);
|
|
770
889
|
}
|
|
890
|
+
const at = compactCdpMethodTimestamp(source.at || "");
|
|
891
|
+
if (at) compact.at = at;
|
|
892
|
+
|
|
893
|
+
const candidate = compactDomStaleCandidateForStatus(source.candidate);
|
|
894
|
+
if (candidate) compact.candidate = candidate;
|
|
895
|
+
const error = compactListReadStaleDiagnosticForStatus(source.error);
|
|
896
|
+
if (error) compact.error = error;
|
|
897
|
+
const preRecoveryRoots = compactDomStaleRootIdentityForStatus(source.pre_recovery_roots);
|
|
898
|
+
if (preRecoveryRoots) compact.pre_recovery_roots = preRecoveryRoots;
|
|
899
|
+
const postRecoveryRoots = compactDomStaleRootIdentityForStatus(source.post_recovery_roots);
|
|
900
|
+
if (postRecoveryRoots) compact.post_recovery_roots = postRecoveryRoots;
|
|
901
|
+
const candidateList = compactDomStaleNumericRecordForStatus(source.candidate_list);
|
|
902
|
+
if (candidateList) compact.candidate_list = candidateList;
|
|
903
|
+
const counters = compactDomStaleNumericRecordForStatus(source.counters);
|
|
904
|
+
if (counters) compact.counters = counters;
|
|
905
|
+
const lifecycleTimeline = compactDomStaleLifecycleTimelineForStatus(source.lifecycle_timeline);
|
|
906
|
+
if (lifecycleTimeline.length) compact.lifecycle_timeline = lifecycleTimeline;
|
|
907
|
+
const recovery = compactDomStaleRecoveryForStatus(source.recovery);
|
|
908
|
+
if (recovery) compact.recovery = recovery;
|
|
771
909
|
return Object.keys(compact).length ? compact : null;
|
|
772
910
|
}
|
|
911
|
+
|
|
912
|
+
function compactDomStaleForensicsForStatus(value) {
|
|
913
|
+
if (!Array.isArray(value)) return [];
|
|
914
|
+
return value
|
|
915
|
+
.map((item) => compactDomStaleForensicForStatus(item))
|
|
916
|
+
.filter(Boolean)
|
|
917
|
+
.slice(-12);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
function compactListReadStaleDiagnosticsForStatus(value) {
|
|
921
|
+
if (!Array.isArray(value)) return [];
|
|
922
|
+
return value
|
|
923
|
+
.map((item) => compactListReadStaleDiagnosticForStatus(item))
|
|
924
|
+
.filter(Boolean)
|
|
925
|
+
.slice(-12);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
function compactListReadStaleCheckpointEvent(value) {
|
|
929
|
+
const source = plainRecord(value);
|
|
930
|
+
if (!Object.keys(source).length) return null;
|
|
931
|
+
const compact = {};
|
|
932
|
+
const diagnostic = compactListReadStaleDiagnosticForStatus(source.diagnostic || source.trigger);
|
|
933
|
+
if (diagnostic) compact.diagnostic = diagnostic;
|
|
934
|
+
const recentDiagnostics = compactListReadStaleDiagnosticsForStatus(source.recent_diagnostics);
|
|
935
|
+
if (recentDiagnostics.length) compact.recent_diagnostics = recentDiagnostics;
|
|
936
|
+
for (const key of ["recovery_count", "recovery_applied_count"]) {
|
|
937
|
+
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
938
|
+
}
|
|
939
|
+
if (source.recovery_error) {
|
|
940
|
+
const recoveryError = compactListReadStaleDiagnosticForStatus(source.recovery_error);
|
|
941
|
+
if (recoveryError) compact.recovery_error = recoveryError;
|
|
942
|
+
}
|
|
943
|
+
if (source.candidate_list) {
|
|
944
|
+
const candidateList = plainRecord(source.candidate_list);
|
|
945
|
+
compact.candidate_list = {};
|
|
946
|
+
for (const key of ["seen_count", "queued_count", "processed_count", "read_error_count", "scroll_count"]) {
|
|
947
|
+
if (Number.isInteger(candidateList[key]) && candidateList[key] >= 0) {
|
|
948
|
+
compact.candidate_list[key] = candidateList[key];
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
return Object.keys(compact).length ? compact : null;
|
|
953
|
+
}
|
|
773
954
|
|
|
774
955
|
function compactRecommendSummaryForStatus(summary) {
|
|
775
956
|
if (!summary || typeof summary !== "object" || Array.isArray(summary)) return null;
|
|
@@ -817,7 +998,7 @@ function compactRecommendSummaryForStatus(summary) {
|
|
|
817
998
|
restLevel: normalizeText(summary.human_behavior.restLevel || summary.human_behavior.rest_level || "")
|
|
818
999
|
};
|
|
819
1000
|
}
|
|
820
|
-
if (summary.human_rest) {
|
|
1001
|
+
if (summary.human_rest) {
|
|
821
1002
|
const humanRest = plainRecord(summary.human_rest);
|
|
822
1003
|
compact.human_rest = {
|
|
823
1004
|
enabled: humanRest.enabled === true,
|
|
@@ -825,23 +1006,27 @@ function compactRecommendSummaryForStatus(summary) {
|
|
|
825
1006
|
rest_count: compactPositiveInteger(humanRest.rest_count ?? humanRest.count, null),
|
|
826
1007
|
total_pause_ms: compactPositiveInteger(humanRest.total_pause_ms ?? humanRest.pause_ms, null)
|
|
827
1008
|
};
|
|
828
|
-
}
|
|
829
|
-
for (const key of [
|
|
830
|
-
"list_read_stale_recovery_attempts",
|
|
831
|
-
"list_read_stale_recovery_applied",
|
|
832
|
-
"list_read_stale_recoveries"
|
|
833
|
-
]) {
|
|
834
|
-
if (Number.isInteger(summary[key]) && summary[key] >= 0) compact[key] = summary[key];
|
|
835
|
-
}
|
|
836
|
-
if (summary.last_list_read_recovery_mode) {
|
|
837
|
-
compact.last_list_read_recovery_mode = normalizeText(summary.last_list_read_recovery_mode).slice(0, 100);
|
|
838
|
-
}
|
|
839
|
-
const lastStaleDiagnostic = compactListReadStaleDiagnosticForStatus(
|
|
840
|
-
summary.last_list_read_stale_diagnostic
|
|
841
|
-
);
|
|
842
|
-
if (lastStaleDiagnostic) compact.last_list_read_stale_diagnostic = lastStaleDiagnostic;
|
|
1009
|
+
}
|
|
1010
|
+
for (const key of [
|
|
1011
|
+
"list_read_stale_recovery_attempts",
|
|
1012
|
+
"list_read_stale_recovery_applied",
|
|
1013
|
+
"list_read_stale_recoveries"
|
|
1014
|
+
]) {
|
|
1015
|
+
if (Number.isInteger(summary[key]) && summary[key] >= 0) compact[key] = summary[key];
|
|
1016
|
+
}
|
|
1017
|
+
if (summary.last_list_read_recovery_mode) {
|
|
1018
|
+
compact.last_list_read_recovery_mode = normalizeText(summary.last_list_read_recovery_mode).slice(0, 100);
|
|
1019
|
+
}
|
|
1020
|
+
const lastStaleDiagnostic = compactListReadStaleDiagnosticForStatus(
|
|
1021
|
+
summary.last_list_read_stale_diagnostic
|
|
1022
|
+
);
|
|
1023
|
+
if (lastStaleDiagnostic) compact.last_list_read_stale_diagnostic = lastStaleDiagnostic;
|
|
843
1024
|
const staleDiagnostics = compactListReadStaleDiagnosticsForStatus(summary.list_read_stale_diagnostics);
|
|
844
1025
|
if (staleDiagnostics.length) compact.list_read_stale_diagnostics = staleDiagnostics;
|
|
1026
|
+
const domStaleForensic = compactDomStaleForensicForStatus(summary.dom_stale_forensic);
|
|
1027
|
+
if (domStaleForensic) compact.dom_stale_forensic = domStaleForensic;
|
|
1028
|
+
const domStaleForensics = compactDomStaleForensicsForStatus(summary.dom_stale_forensics);
|
|
1029
|
+
if (domStaleForensics.length) compact.dom_stale_forensics = domStaleForensics;
|
|
845
1030
|
return compact;
|
|
846
1031
|
}
|
|
847
1032
|
|
|
@@ -856,19 +1041,23 @@ function compactRecommendCheckpointForStatus(checkpoint) {
|
|
|
856
1041
|
} else if (Number.isInteger(checkpoint.results_count)) {
|
|
857
1042
|
compact.results_count = checkpoint.results_count;
|
|
858
1043
|
}
|
|
859
|
-
for (const key of STATUS_COUNT_KEYS) {
|
|
860
|
-
if (Number.isInteger(checkpoint[key])) compact[key] = checkpoint[key];
|
|
861
|
-
}
|
|
1044
|
+
for (const key of STATUS_COUNT_KEYS) {
|
|
1045
|
+
if (Number.isInteger(checkpoint[key])) compact[key] = checkpoint[key];
|
|
1046
|
+
}
|
|
862
1047
|
for (const key of [
|
|
863
|
-
"list_read_stale_recovery",
|
|
864
|
-
"list_read_stale_recovery_applied",
|
|
865
|
-
"list_read_stale_recovered",
|
|
866
|
-
"list_read_stale_recovery_exhausted",
|
|
867
|
-
"list_read_stale_recovery_failed"
|
|
868
|
-
]) {
|
|
1048
|
+
"list_read_stale_recovery",
|
|
1049
|
+
"list_read_stale_recovery_applied",
|
|
1050
|
+
"list_read_stale_recovered",
|
|
1051
|
+
"list_read_stale_recovery_exhausted",
|
|
1052
|
+
"list_read_stale_recovery_failed"
|
|
1053
|
+
]) {
|
|
869
1054
|
const event = compactListReadStaleCheckpointEvent(checkpoint[key]);
|
|
870
1055
|
if (event) compact[key] = event;
|
|
871
1056
|
}
|
|
1057
|
+
const domStaleForensic = compactDomStaleForensicForStatus(checkpoint.dom_stale_forensic);
|
|
1058
|
+
if (domStaleForensic) compact.dom_stale_forensic = domStaleForensic;
|
|
1059
|
+
const domStaleForensics = compactDomStaleForensicsForStatus(checkpoint.dom_stale_forensics);
|
|
1060
|
+
if (domStaleForensics.length) compact.dom_stale_forensics = domStaleForensics;
|
|
872
1061
|
return compact;
|
|
873
1062
|
}
|
|
874
1063
|
|
|
@@ -1268,16 +1457,16 @@ function persistRecommendRunSnapshot(snapshot, {
|
|
|
1268
1457
|
const artifacts = getRecommendRunArtifacts(normalized.run_id);
|
|
1269
1458
|
if (!artifacts) return normalized;
|
|
1270
1459
|
const existing = readJsonFile(artifacts.run_state_path);
|
|
1271
|
-
normalized.control = mergePersistedControlRequest(normalized, existing);
|
|
1272
|
-
normalized = coerceCanceledTerminalSnapshot(normalized, existing);
|
|
1273
|
-
if (persistActiveCheckpoint) {
|
|
1274
|
-
persistRecommendCheckpointSnapshot(snapshot);
|
|
1275
|
-
}
|
|
1276
|
-
const cdpEvidence = buildPersistedCdpEvidence({
|
|
1277
|
-
meta: getRecommendRunMeta(normalized.run_id),
|
|
1278
|
-
persisted: existing || {}
|
|
1279
|
-
});
|
|
1280
|
-
const payload = {
|
|
1460
|
+
normalized.control = mergePersistedControlRequest(normalized, existing);
|
|
1461
|
+
normalized = coerceCanceledTerminalSnapshot(normalized, existing);
|
|
1462
|
+
if (persistActiveCheckpoint) {
|
|
1463
|
+
persistRecommendCheckpointSnapshot(snapshot);
|
|
1464
|
+
}
|
|
1465
|
+
const cdpEvidence = buildPersistedCdpEvidence({
|
|
1466
|
+
meta: getRecommendRunMeta(normalized.run_id),
|
|
1467
|
+
persisted: existing || {}
|
|
1468
|
+
});
|
|
1469
|
+
const payload = {
|
|
1281
1470
|
run_id: normalized.run_id,
|
|
1282
1471
|
mode: normalized.mode,
|
|
1283
1472
|
state: normalized.state,
|
|
@@ -1293,14 +1482,14 @@ function persistRecommendRunSnapshot(snapshot, {
|
|
|
1293
1482
|
context: normalized.context,
|
|
1294
1483
|
control: normalized.control,
|
|
1295
1484
|
resume: normalized.resume,
|
|
1296
|
-
error: normalized.error,
|
|
1297
|
-
recovery: normalized.recovery,
|
|
1298
|
-
result: normalized.result,
|
|
1299
|
-
summary: normalized.summary,
|
|
1300
|
-
checkpoint: normalized.checkpoint,
|
|
1301
|
-
artifacts: normalized.artifacts,
|
|
1302
|
-
...cdpEvidence
|
|
1303
|
-
};
|
|
1485
|
+
error: normalized.error,
|
|
1486
|
+
recovery: normalized.recovery,
|
|
1487
|
+
result: normalized.result,
|
|
1488
|
+
summary: normalized.summary,
|
|
1489
|
+
checkpoint: normalized.checkpoint,
|
|
1490
|
+
artifacts: normalized.artifacts,
|
|
1491
|
+
...cdpEvidence
|
|
1492
|
+
};
|
|
1304
1493
|
writeJsonAtomic(artifacts.run_state_path, payload);
|
|
1305
1494
|
return normalized;
|
|
1306
1495
|
}
|
|
@@ -1373,18 +1562,18 @@ function persistRecommendLifecycleSnapshot(snapshot, event = {}) {
|
|
|
1373
1562
|
});
|
|
1374
1563
|
}
|
|
1375
1564
|
|
|
1376
|
-
function attachMethodEvidence(payload, runId) {
|
|
1377
|
-
const meta = getRecommendRunMeta(runId);
|
|
1378
|
-
const methodLog = meta.methodLog || [];
|
|
1379
|
-
assertNoForbiddenCdpCalls(methodLog);
|
|
1380
|
-
return {
|
|
1381
|
-
...payload,
|
|
1382
|
-
...buildPersistedCdpEvidence({
|
|
1383
|
-
meta,
|
|
1384
|
-
persisted: readRecommendRunState(runId) || {}
|
|
1385
|
-
})
|
|
1386
|
-
};
|
|
1387
|
-
}
|
|
1565
|
+
function attachMethodEvidence(payload, runId) {
|
|
1566
|
+
const meta = getRecommendRunMeta(runId);
|
|
1567
|
+
const methodLog = meta.methodLog || [];
|
|
1568
|
+
assertNoForbiddenCdpCalls(methodLog);
|
|
1569
|
+
return {
|
|
1570
|
+
...payload,
|
|
1571
|
+
...buildPersistedCdpEvidence({
|
|
1572
|
+
meta,
|
|
1573
|
+
persisted: readRecommendRunState(runId) || {}
|
|
1574
|
+
})
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1388
1577
|
|
|
1389
1578
|
function compactRecommendJobListOption(option, index) {
|
|
1390
1579
|
const label = normalizeText(option?.label);
|
|
@@ -1935,13 +2124,13 @@ function buildRecommendFilter(parsed, args = {}) {
|
|
|
1935
2124
|
return { enabled: false };
|
|
1936
2125
|
}
|
|
1937
2126
|
|
|
1938
|
-
const groups = [{
|
|
1939
|
-
group: "activity",
|
|
1940
|
-
labels: [parsed.searchParams?.activity_level || "不限"],
|
|
1941
|
-
selectAllLabels: false,
|
|
1942
|
-
allowUnlimited: true,
|
|
1943
|
-
verifySticky: true
|
|
1944
|
-
}];
|
|
2127
|
+
const groups = [{
|
|
2128
|
+
group: "activity",
|
|
2129
|
+
labels: [parsed.searchParams?.activity_level || "不限"],
|
|
2130
|
+
selectAllLabels: false,
|
|
2131
|
+
allowUnlimited: true,
|
|
2132
|
+
verifySticky: true
|
|
2133
|
+
}];
|
|
1945
2134
|
const recentNotView = withoutUnlimited(parsed.searchParams?.recent_not_view);
|
|
1946
2135
|
if (recentNotView.length) {
|
|
1947
2136
|
groups.push({
|
|
@@ -1978,12 +2167,12 @@ function buildRecommendFilter(parsed, args = {}) {
|
|
|
1978
2167
|
});
|
|
1979
2168
|
}
|
|
1980
2169
|
|
|
1981
|
-
return {
|
|
1982
|
-
enabled: true,
|
|
1983
|
-
currentCityOnly: parsed.searchParams?.current_city_only === true,
|
|
1984
|
-
filterGroups: groups
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
2170
|
+
return {
|
|
2171
|
+
enabled: true,
|
|
2172
|
+
currentCityOnly: parsed.searchParams?.current_city_only === true,
|
|
2173
|
+
filterGroups: groups
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
1987
2176
|
|
|
1988
2177
|
function normalizeRecommendStartInput(args = {}, parsed, configResolution = null) {
|
|
1989
2178
|
const confirmation = args.confirmation || {};
|
|
@@ -2071,23 +2260,23 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
|
|
|
2071
2260
|
) || "low",
|
|
2072
2261
|
imageOutputDir: resolveBossConfiguredOutputDir("", getRunsDir()),
|
|
2073
2262
|
humanRestEnabled: humanBehavior.restEnabled,
|
|
2074
|
-
humanBehavior,
|
|
2075
|
-
skipRecentColleagueContacted: normalized.skipRecentColleagueContacted,
|
|
2076
|
-
colleagueContactWindowDays: normalized.colleagueContactWindowDays,
|
|
2077
|
-
debugTestMode: isDebugTestMode(args),
|
|
2078
|
-
debugForceListEndAfterProcessed: parsePositiveInteger(
|
|
2079
|
-
args.debug_force_list_end_after_processed,
|
|
2080
|
-
null
|
|
2081
|
-
),
|
|
2082
|
-
debugForceContextRecoveryAfterProcessed: parsePositiveInteger(
|
|
2083
|
-
args.debug_force_context_recovery_after_processed,
|
|
2084
|
-
null
|
|
2085
|
-
),
|
|
2086
|
-
debugForceCdpReconnectAfterProcessed: parsePositiveInteger(
|
|
2087
|
-
args.debug_force_cdp_reconnect_after_processed,
|
|
2088
|
-
null
|
|
2089
|
-
),
|
|
2090
|
-
name: "mcp-recommend-pipeline-run",
|
|
2263
|
+
humanBehavior,
|
|
2264
|
+
skipRecentColleagueContacted: normalized.skipRecentColleagueContacted,
|
|
2265
|
+
colleagueContactWindowDays: normalized.colleagueContactWindowDays,
|
|
2266
|
+
debugTestMode: isDebugTestMode(args),
|
|
2267
|
+
debugForceListEndAfterProcessed: parsePositiveInteger(
|
|
2268
|
+
args.debug_force_list_end_after_processed,
|
|
2269
|
+
null
|
|
2270
|
+
),
|
|
2271
|
+
debugForceContextRecoveryAfterProcessed: parsePositiveInteger(
|
|
2272
|
+
args.debug_force_context_recovery_after_processed,
|
|
2273
|
+
null
|
|
2274
|
+
),
|
|
2275
|
+
debugForceCdpReconnectAfterProcessed: parsePositiveInteger(
|
|
2276
|
+
args.debug_force_cdp_reconnect_after_processed,
|
|
2277
|
+
null
|
|
2278
|
+
),
|
|
2279
|
+
name: "mcp-recommend-pipeline-run",
|
|
2091
2280
|
parsed
|
|
2092
2281
|
};
|
|
2093
2282
|
}
|
|
@@ -2379,19 +2568,19 @@ export function getRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2379
2568
|
run: compactRecommendRunForStatus(normalizedRun)
|
|
2380
2569
|
}, runId);
|
|
2381
2570
|
} catch {
|
|
2382
|
-
const persisted = readRecommendRunState(runId);
|
|
2383
|
-
if (persisted) {
|
|
2384
|
-
const reconciled = compactRecommendRunForStatus(reconcilePersistedRecommendRunIfNeeded(persisted));
|
|
2385
|
-
const persistedEvidence = readRecommendRunState(runId) || persisted;
|
|
2386
|
-
return attachPersistedCdpEvidence({
|
|
2387
|
-
status: "RUN_STATUS",
|
|
2388
|
-
run: reconciled,
|
|
2389
|
-
persistence: {
|
|
2390
|
-
source: "disk",
|
|
2391
|
-
active_control_available: false,
|
|
2392
|
-
stale_process_reconciled: reconciled?.state !== persisted.state
|
|
2393
|
-
}
|
|
2394
|
-
}, persistedEvidence);
|
|
2571
|
+
const persisted = readRecommendRunState(runId);
|
|
2572
|
+
if (persisted) {
|
|
2573
|
+
const reconciled = compactRecommendRunForStatus(reconcilePersistedRecommendRunIfNeeded(persisted));
|
|
2574
|
+
const persistedEvidence = readRecommendRunState(runId) || persisted;
|
|
2575
|
+
return attachPersistedCdpEvidence({
|
|
2576
|
+
status: "RUN_STATUS",
|
|
2577
|
+
run: reconciled,
|
|
2578
|
+
persistence: {
|
|
2579
|
+
source: "disk",
|
|
2580
|
+
active_control_available: false,
|
|
2581
|
+
stale_process_reconciled: reconciled?.state !== persisted.state
|
|
2582
|
+
}
|
|
2583
|
+
}, persistedEvidence);
|
|
2395
2584
|
}
|
|
2396
2585
|
return {
|
|
2397
2586
|
status: "FAILED",
|
|
@@ -2432,13 +2621,13 @@ export function pauseRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2432
2621
|
message: "暂停请求已接收,将在当前候选人处理完成后进入 paused。"
|
|
2433
2622
|
}, runId);
|
|
2434
2623
|
} catch {
|
|
2435
|
-
const persisted = readRecommendRunState(runId);
|
|
2436
|
-
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2437
|
-
return attachPersistedCdpEvidence({
|
|
2438
|
-
status: "PAUSE_IGNORED",
|
|
2439
|
-
run: compactRecommendRunForStatus(persisted),
|
|
2440
|
-
message: "目标任务已结束,无需暂停。"
|
|
2441
|
-
}, persisted);
|
|
2624
|
+
const persisted = readRecommendRunState(runId);
|
|
2625
|
+
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2626
|
+
return attachPersistedCdpEvidence({
|
|
2627
|
+
status: "PAUSE_IGNORED",
|
|
2628
|
+
run: compactRecommendRunForStatus(persisted),
|
|
2629
|
+
message: "目标任务已结束,无需暂停。"
|
|
2630
|
+
}, persisted);
|
|
2442
2631
|
}
|
|
2443
2632
|
return getRecommendPipelineRunTool({ args });
|
|
2444
2633
|
}
|
|
@@ -2486,11 +2675,11 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2486
2675
|
message: "已恢复 Recommend run,请使用 get_recommend_pipeline_run 按需轮询。"
|
|
2487
2676
|
}, runId);
|
|
2488
2677
|
} catch {
|
|
2489
|
-
const persisted = readRecommendRunState(runId);
|
|
2490
|
-
if (persisted) {
|
|
2491
|
-
return attachPersistedCdpEvidence({
|
|
2492
|
-
status: "FAILED",
|
|
2493
|
-
error: {
|
|
2678
|
+
const persisted = readRecommendRunState(runId);
|
|
2679
|
+
if (persisted) {
|
|
2680
|
+
return attachPersistedCdpEvidence({
|
|
2681
|
+
status: "FAILED",
|
|
2682
|
+
error: {
|
|
2494
2683
|
code: TERMINAL_STATUSES.has(persisted.state) ? "RUN_ALREADY_TERMINATED" : "RUN_NOT_ACTIVE",
|
|
2495
2684
|
message: TERMINAL_STATUSES.has(persisted.state)
|
|
2496
2685
|
? "目标任务已结束,无法继续。"
|
|
@@ -2498,11 +2687,11 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2498
2687
|
retryable: !TERMINAL_STATUSES.has(persisted.state)
|
|
2499
2688
|
},
|
|
2500
2689
|
run: compactRecommendRunForStatus(persisted),
|
|
2501
|
-
persistence: {
|
|
2502
|
-
source: "disk",
|
|
2503
|
-
active_control_available: false
|
|
2504
|
-
}
|
|
2505
|
-
}, persisted);
|
|
2690
|
+
persistence: {
|
|
2691
|
+
source: "disk",
|
|
2692
|
+
active_control_available: false
|
|
2693
|
+
}
|
|
2694
|
+
}, persisted);
|
|
2506
2695
|
}
|
|
2507
2696
|
return getRecommendPipelineRunTool({ args });
|
|
2508
2697
|
}
|
|
@@ -2528,13 +2717,13 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2528
2717
|
message: "已收到取消请求,将在当前候选人处理完成后安全停止。"
|
|
2529
2718
|
}, runId);
|
|
2530
2719
|
} catch {
|
|
2531
|
-
const persisted = readRecommendRunState(runId);
|
|
2532
|
-
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2533
|
-
return attachPersistedCdpEvidence({
|
|
2534
|
-
status: "CANCEL_IGNORED",
|
|
2535
|
-
run: compactRecommendRunForStatus(persisted),
|
|
2536
|
-
message: "目标任务已结束,无需取消。"
|
|
2537
|
-
}, persisted);
|
|
2720
|
+
const persisted = readRecommendRunState(runId);
|
|
2721
|
+
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2722
|
+
return attachPersistedCdpEvidence({
|
|
2723
|
+
status: "CANCEL_IGNORED",
|
|
2724
|
+
run: compactRecommendRunForStatus(persisted),
|
|
2725
|
+
message: "目标任务已结束,无需取消。"
|
|
2726
|
+
}, persisted);
|
|
2538
2727
|
}
|
|
2539
2728
|
const cancelMessage = "已收到取消请求,将由 detached worker 在下一个安全边界停止。";
|
|
2540
2729
|
const patched = patchPersistedRecommendRunControl(runId, {
|
|
@@ -2544,18 +2733,18 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2544
2733
|
cancel_requested: true
|
|
2545
2734
|
}, {
|
|
2546
2735
|
message: cancelMessage
|
|
2547
|
-
});
|
|
2548
|
-
if (patched) {
|
|
2549
|
-
return attachPersistedCdpEvidence({
|
|
2550
|
-
status: "CANCEL_REQUESTED",
|
|
2551
|
-
run: compactRecommendRunForStatus(patched),
|
|
2736
|
+
});
|
|
2737
|
+
if (patched) {
|
|
2738
|
+
return attachPersistedCdpEvidence({
|
|
2739
|
+
status: "CANCEL_REQUESTED",
|
|
2740
|
+
run: compactRecommendRunForStatus(patched),
|
|
2552
2741
|
message: cancelMessage,
|
|
2553
2742
|
persistence: {
|
|
2554
2743
|
source: "disk",
|
|
2555
|
-
active_control_available: false,
|
|
2556
|
-
detached_control_requested: true
|
|
2557
|
-
}
|
|
2558
|
-
}, patched);
|
|
2744
|
+
active_control_available: false,
|
|
2745
|
+
detached_control_requested: true
|
|
2746
|
+
}
|
|
2747
|
+
}, patched);
|
|
2559
2748
|
}
|
|
2560
2749
|
return getRecommendPipelineRunTool({ args });
|
|
2561
2750
|
}
|