@reconcrap/boss-recommend-mcp 2.1.22 → 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 +14 -8
- 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 +291 -114
- 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 +11 -2
- package/src/core/reporting/legacy-csv.js +12 -12
- package/src/core/run/detached-launcher.js +305 -0
- package/src/core/run/index.js +112 -42
- 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 -3
- 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 +410 -329
- package/src/domains/recommend/roots.js +80 -80
- package/src/domains/recommend/run-service.js +1783 -592
- 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 +124 -5
- package/src/parser.js +1296 -1296
- package/src/recommend-mcp.js +515 -80
- package/src/recommend-scheduler.js +66 -0
package/src/recommend-mcp.js
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
createBossLoginRequiredError,
|
|
9
9
|
detectBossLoginState,
|
|
10
10
|
enableDomains,
|
|
11
|
+
FORBIDDEN_CDP_METHODS,
|
|
11
12
|
getMainFrameUrl,
|
|
12
13
|
isBossLoginUrl,
|
|
13
14
|
waitForMainFrameUrl,
|
|
@@ -284,6 +285,15 @@ function collectRecommendDebugTestOptions(args = {}, normalized = {}) {
|
|
|
284
285
|
if (parseNonNegativeInteger(args.detail_limit, null) === 0) reasons.push("detail_limit=0");
|
|
285
286
|
if (args.no_filter === true) reasons.push("no_filter");
|
|
286
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
297
|
if (args.dry_run_post_action === true) reasons.push("dry_run_post_action");
|
|
288
298
|
if (args.execute_post_action === false && normalized.postAction && normalized.postAction !== "none") {
|
|
289
299
|
reasons.push("execute_post_action=false");
|
|
@@ -306,18 +316,44 @@ function resolveRecommendDetailLimit(args = {}, normalized = {}) {
|
|
|
306
316
|
function methodSummary(methodLog = []) {
|
|
307
317
|
const summary = {};
|
|
308
318
|
for (const entry of methodLog || []) {
|
|
309
|
-
|
|
319
|
+
const method = compactCdpMethodName(entry?.method || entry || "");
|
|
320
|
+
if (!method) continue;
|
|
321
|
+
summary[method] = (summary[method] || 0) + 1;
|
|
310
322
|
}
|
|
311
323
|
return summary;
|
|
312
324
|
}
|
|
313
325
|
|
|
314
|
-
function
|
|
315
|
-
|
|
316
|
-
return
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
+
function compactMethodLogForStatus(methodLog = []) {
|
|
340
|
+
if (!Array.isArray(methodLog)) return [];
|
|
341
|
+
return methodLog
|
|
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
|
+
})
|
|
354
|
+
.filter((entry) => Boolean(entry.method))
|
|
355
|
+
.slice(-STATUS_METHOD_LOG_TAIL_LIMIT);
|
|
356
|
+
}
|
|
321
357
|
|
|
322
358
|
function clonePlain(value, fallback = null) {
|
|
323
359
|
try {
|
|
@@ -336,6 +372,126 @@ function nonEmptyRecord(value) {
|
|
|
336
372
|
return Object.keys(record).length ? record : null;
|
|
337
373
|
}
|
|
338
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
|
+
}
|
|
494
|
+
|
|
339
495
|
function normalizeRunId(runId) {
|
|
340
496
|
const normalized = normalizeText(runId);
|
|
341
497
|
if (!normalized || normalized.includes("/") || normalized.includes("\\")) return "";
|
|
@@ -382,12 +538,12 @@ function readJsonFile(filePath) {
|
|
|
382
538
|
|
|
383
539
|
function recommendSearchParamsForCsv(searchParams = {}) {
|
|
384
540
|
return {
|
|
385
|
-
school_tag: Object.prototype.hasOwnProperty.call(searchParams, "school_tag") ? searchParams.school_tag : "不限",
|
|
386
|
-
degree: Object.prototype.hasOwnProperty.call(searchParams, "degree") ? searchParams.degree : "不限",
|
|
387
|
-
gender: Object.prototype.hasOwnProperty.call(searchParams, "gender") ? searchParams.gender : "不限",
|
|
388
|
-
recent_not_view: Object.prototype.hasOwnProperty.call(searchParams, "recent_not_view") ? searchParams.recent_not_view : "不限",
|
|
389
|
-
current_city_only: Object.prototype.hasOwnProperty.call(searchParams, "current_city_only") ? searchParams.current_city_only : false,
|
|
390
|
-
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 : "不限"
|
|
391
547
|
};
|
|
392
548
|
}
|
|
393
549
|
|
|
@@ -426,12 +582,12 @@ function selectedRecommendJobForCsv(meta = {}, snapshot = {}) {
|
|
|
426
582
|
function buildRecommendCsvInputRows(snapshot = {}, meta = {}) {
|
|
427
583
|
const { context, confirmation, overrides, followUp, shared } = getSnapshotRequestContext(snapshot);
|
|
428
584
|
const searchParams = recommendSearchParamsForCsv(meta.parsed?.searchParams || {
|
|
429
|
-
school_tag: overrides.school_tag ?? confirmation.school_tag_value,
|
|
430
|
-
degree: overrides.degree ?? confirmation.degree_value,
|
|
431
|
-
gender: overrides.gender ?? confirmation.gender_value,
|
|
432
|
-
recent_not_view: overrides.recent_not_view ?? confirmation.recent_not_view_value,
|
|
433
|
-
current_city_only: overrides.current_city_only ?? false,
|
|
434
|
-
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 ?? "不限"
|
|
435
591
|
});
|
|
436
592
|
const parsedScreenParams = meta.parsed?.screenParams || {};
|
|
437
593
|
const screenParams = {
|
|
@@ -506,7 +662,7 @@ function normalizeLegacyProgress(progress = {}, summary = null) {
|
|
|
506
662
|
: Number.isInteger(summary?.passed)
|
|
507
663
|
? summary.passed
|
|
508
664
|
: 0;
|
|
509
|
-
|
|
665
|
+
const normalized = {
|
|
510
666
|
...progress,
|
|
511
667
|
processed,
|
|
512
668
|
inspected: processed,
|
|
@@ -516,7 +672,28 @@ function normalizeLegacyProgress(progress = {}, summary = null) {
|
|
|
516
672
|
greet_count: Number.isInteger(progress.greet_count) ? progress.greet_count : 0,
|
|
517
673
|
post_action_clicked: Number.isInteger(progress.post_action_clicked) ? progress.post_action_clicked : 0
|
|
518
674
|
};
|
|
519
|
-
|
|
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
|
+
}
|
|
680
|
+
if (Object.prototype.hasOwnProperty.call(normalized, "list_read_stale_diagnostics")) {
|
|
681
|
+
normalized.list_read_stale_diagnostics = compactListReadStaleDiagnosticsForStatus(
|
|
682
|
+
normalized.list_read_stale_diagnostics
|
|
683
|
+
);
|
|
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
|
+
}
|
|
695
|
+
return normalized;
|
|
696
|
+
}
|
|
520
697
|
|
|
521
698
|
const STATUS_COUNT_KEYS = [
|
|
522
699
|
"processed",
|
|
@@ -550,6 +727,231 @@ function compactSmallRecord(value, fallback = null) {
|
|
|
550
727
|
return clonePlain(record, fallback);
|
|
551
728
|
}
|
|
552
729
|
|
|
730
|
+
function compactListReadStaleDiagnosticForStatus(value) {
|
|
731
|
+
const source = plainRecord(value);
|
|
732
|
+
if (!Object.keys(source).length) return null;
|
|
733
|
+
const compact = {};
|
|
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
|
+
]) {
|
|
745
|
+
const text = normalizeText(source[key] || "");
|
|
746
|
+
if (text) compact[key] = text.slice(0, key === "message" ? 500 : 200);
|
|
747
|
+
}
|
|
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
|
+
]) {
|
|
755
|
+
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
756
|
+
}
|
|
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
|
+
]) {
|
|
766
|
+
if (typeof source[key] === "boolean") compact[key] = source[key];
|
|
767
|
+
}
|
|
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
|
+
}
|
|
772
|
+
if (Array.isArray(source.cdp_param_keys)) {
|
|
773
|
+
compact.cdp_param_keys = source.cdp_param_keys
|
|
774
|
+
.map((key) => normalizeText(key))
|
|
775
|
+
.filter((key) => /^[A-Za-z][A-Za-z0-9_]*$/.test(key))
|
|
776
|
+
.slice(0, 20);
|
|
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
|
+
}
|
|
792
|
+
return Object.keys(compact).length ? compact : null;
|
|
793
|
+
}
|
|
794
|
+
|
|
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) {
|
|
826
|
+
if (!Array.isArray(value)) return [];
|
|
827
|
+
return value
|
|
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
|
+
})
|
|
844
|
+
.filter(Boolean)
|
|
845
|
+
.slice(-20);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
function compactDomStaleCandidateForStatus(value) {
|
|
849
|
+
const source = plainRecord(value);
|
|
850
|
+
if (!Object.keys(source).length) return null;
|
|
851
|
+
const compact = {};
|
|
852
|
+
for (const key of ["index", "card_node_id", "visible_index", "failing_list_node_id"]) {
|
|
853
|
+
if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
|
|
854
|
+
}
|
|
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);
|
|
867
|
+
}
|
|
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);
|
|
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;
|
|
909
|
+
return Object.keys(compact).length ? compact : null;
|
|
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
|
+
}
|
|
954
|
+
|
|
553
955
|
function compactRecommendSummaryForStatus(summary) {
|
|
554
956
|
if (!summary || typeof summary !== "object" || Array.isArray(summary)) return null;
|
|
555
957
|
const compact = {
|
|
@@ -605,8 +1007,28 @@ function compactRecommendSummaryForStatus(summary) {
|
|
|
605
1007
|
total_pause_ms: compactPositiveInteger(humanRest.total_pause_ms ?? humanRest.pause_ms, null)
|
|
606
1008
|
};
|
|
607
1009
|
}
|
|
608
|
-
|
|
609
|
-
|
|
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;
|
|
1024
|
+
const staleDiagnostics = compactListReadStaleDiagnosticsForStatus(summary.list_read_stale_diagnostics);
|
|
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;
|
|
1030
|
+
return compact;
|
|
1031
|
+
}
|
|
610
1032
|
|
|
611
1033
|
function compactRecommendCheckpointForStatus(checkpoint) {
|
|
612
1034
|
if (!checkpoint || typeof checkpoint !== "object" || Array.isArray(checkpoint)) return {};
|
|
@@ -622,8 +1044,22 @@ function compactRecommendCheckpointForStatus(checkpoint) {
|
|
|
622
1044
|
for (const key of STATUS_COUNT_KEYS) {
|
|
623
1045
|
if (Number.isInteger(checkpoint[key])) compact[key] = checkpoint[key];
|
|
624
1046
|
}
|
|
625
|
-
|
|
626
|
-
|
|
1047
|
+
for (const key of [
|
|
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
|
+
]) {
|
|
1054
|
+
const event = compactListReadStaleCheckpointEvent(checkpoint[key]);
|
|
1055
|
+
if (event) compact[key] = event;
|
|
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;
|
|
1061
|
+
return compact;
|
|
1062
|
+
}
|
|
627
1063
|
|
|
628
1064
|
function compactRecommendResultForStatus(result) {
|
|
629
1065
|
if (!result || typeof result !== "object" || Array.isArray(result)) return result || null;
|
|
@@ -1026,6 +1462,10 @@ function persistRecommendRunSnapshot(snapshot, {
|
|
|
1026
1462
|
if (persistActiveCheckpoint) {
|
|
1027
1463
|
persistRecommendCheckpointSnapshot(snapshot);
|
|
1028
1464
|
}
|
|
1465
|
+
const cdpEvidence = buildPersistedCdpEvidence({
|
|
1466
|
+
meta: getRecommendRunMeta(normalized.run_id),
|
|
1467
|
+
persisted: existing || {}
|
|
1468
|
+
});
|
|
1029
1469
|
const payload = {
|
|
1030
1470
|
run_id: normalized.run_id,
|
|
1031
1471
|
mode: normalized.mode,
|
|
@@ -1046,7 +1486,9 @@ function persistRecommendRunSnapshot(snapshot, {
|
|
|
1046
1486
|
recovery: normalized.recovery,
|
|
1047
1487
|
result: normalized.result,
|
|
1048
1488
|
summary: normalized.summary,
|
|
1049
|
-
|
|
1489
|
+
checkpoint: normalized.checkpoint,
|
|
1490
|
+
artifacts: normalized.artifacts,
|
|
1491
|
+
...cdpEvidence
|
|
1050
1492
|
};
|
|
1051
1493
|
writeJsonAtomic(artifacts.run_state_path, payload);
|
|
1052
1494
|
return normalized;
|
|
@@ -1126,11 +1568,10 @@ function attachMethodEvidence(payload, runId) {
|
|
|
1126
1568
|
assertNoForbiddenCdpCalls(methodLog);
|
|
1127
1569
|
return {
|
|
1128
1570
|
...payload,
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
chrome: meta.chrome || null
|
|
1571
|
+
...buildPersistedCdpEvidence({
|
|
1572
|
+
meta,
|
|
1573
|
+
persisted: readRecommendRunState(runId) || {}
|
|
1574
|
+
})
|
|
1134
1575
|
};
|
|
1135
1576
|
}
|
|
1136
1577
|
|
|
@@ -1683,13 +2124,13 @@ function buildRecommendFilter(parsed, args = {}) {
|
|
|
1683
2124
|
return { enabled: false };
|
|
1684
2125
|
}
|
|
1685
2126
|
|
|
1686
|
-
const groups = [{
|
|
1687
|
-
group: "activity",
|
|
1688
|
-
labels: [parsed.searchParams?.activity_level || "不限"],
|
|
1689
|
-
selectAllLabels: false,
|
|
1690
|
-
allowUnlimited: true,
|
|
1691
|
-
verifySticky: true
|
|
1692
|
-
}];
|
|
2127
|
+
const groups = [{
|
|
2128
|
+
group: "activity",
|
|
2129
|
+
labels: [parsed.searchParams?.activity_level || "不限"],
|
|
2130
|
+
selectAllLabels: false,
|
|
2131
|
+
allowUnlimited: true,
|
|
2132
|
+
verifySticky: true
|
|
2133
|
+
}];
|
|
1693
2134
|
const recentNotView = withoutUnlimited(parsed.searchParams?.recent_not_view);
|
|
1694
2135
|
if (recentNotView.length) {
|
|
1695
2136
|
groups.push({
|
|
@@ -1726,12 +2167,12 @@ function buildRecommendFilter(parsed, args = {}) {
|
|
|
1726
2167
|
});
|
|
1727
2168
|
}
|
|
1728
2169
|
|
|
1729
|
-
return {
|
|
1730
|
-
enabled: true,
|
|
1731
|
-
currentCityOnly: parsed.searchParams?.current_city_only === true,
|
|
1732
|
-
filterGroups: groups
|
|
1733
|
-
};
|
|
1734
|
-
}
|
|
2170
|
+
return {
|
|
2171
|
+
enabled: true,
|
|
2172
|
+
currentCityOnly: parsed.searchParams?.current_city_only === true,
|
|
2173
|
+
filterGroups: groups
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
1735
2176
|
|
|
1736
2177
|
function normalizeRecommendStartInput(args = {}, parsed, configResolution = null) {
|
|
1737
2178
|
const confirmation = args.confirmation || {};
|
|
@@ -1822,6 +2263,19 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
|
|
|
1822
2263
|
humanBehavior,
|
|
1823
2264
|
skipRecentColleagueContacted: normalized.skipRecentColleagueContacted,
|
|
1824
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
|
+
),
|
|
1825
2279
|
name: "mcp-recommend-pipeline-run",
|
|
1826
2280
|
parsed
|
|
1827
2281
|
};
|
|
@@ -2117,19 +2571,16 @@ export function getRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2117
2571
|
const persisted = readRecommendRunState(runId);
|
|
2118
2572
|
if (persisted) {
|
|
2119
2573
|
const reconciled = compactRecommendRunForStatus(reconcilePersistedRecommendRunIfNeeded(persisted));
|
|
2120
|
-
|
|
2574
|
+
const persistedEvidence = readRecommendRunState(runId) || persisted;
|
|
2575
|
+
return attachPersistedCdpEvidence({
|
|
2121
2576
|
status: "RUN_STATUS",
|
|
2122
2577
|
run: reconciled,
|
|
2123
2578
|
persistence: {
|
|
2124
2579
|
source: "disk",
|
|
2125
2580
|
active_control_available: false,
|
|
2126
2581
|
stale_process_reconciled: reconciled?.state !== persisted.state
|
|
2127
|
-
}
|
|
2128
|
-
|
|
2129
|
-
method_summary: {},
|
|
2130
|
-
method_log: [],
|
|
2131
|
-
chrome: null
|
|
2132
|
-
};
|
|
2582
|
+
}
|
|
2583
|
+
}, persistedEvidence);
|
|
2133
2584
|
}
|
|
2134
2585
|
return {
|
|
2135
2586
|
status: "FAILED",
|
|
@@ -2172,15 +2623,11 @@ export function pauseRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2172
2623
|
} catch {
|
|
2173
2624
|
const persisted = readRecommendRunState(runId);
|
|
2174
2625
|
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2175
|
-
return {
|
|
2626
|
+
return attachPersistedCdpEvidence({
|
|
2176
2627
|
status: "PAUSE_IGNORED",
|
|
2177
2628
|
run: compactRecommendRunForStatus(persisted),
|
|
2178
|
-
message: "目标任务已结束,无需暂停。"
|
|
2179
|
-
|
|
2180
|
-
method_summary: {},
|
|
2181
|
-
method_log: [],
|
|
2182
|
-
chrome: null
|
|
2183
|
-
};
|
|
2629
|
+
message: "目标任务已结束,无需暂停。"
|
|
2630
|
+
}, persisted);
|
|
2184
2631
|
}
|
|
2185
2632
|
return getRecommendPipelineRunTool({ args });
|
|
2186
2633
|
}
|
|
@@ -2230,7 +2677,7 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2230
2677
|
} catch {
|
|
2231
2678
|
const persisted = readRecommendRunState(runId);
|
|
2232
2679
|
if (persisted) {
|
|
2233
|
-
return {
|
|
2680
|
+
return attachPersistedCdpEvidence({
|
|
2234
2681
|
status: "FAILED",
|
|
2235
2682
|
error: {
|
|
2236
2683
|
code: TERMINAL_STATUSES.has(persisted.state) ? "RUN_ALREADY_TERMINATED" : "RUN_NOT_ACTIVE",
|
|
@@ -2243,12 +2690,8 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2243
2690
|
persistence: {
|
|
2244
2691
|
source: "disk",
|
|
2245
2692
|
active_control_available: false
|
|
2246
|
-
}
|
|
2247
|
-
|
|
2248
|
-
method_summary: {},
|
|
2249
|
-
method_log: [],
|
|
2250
|
-
chrome: null
|
|
2251
|
-
};
|
|
2693
|
+
}
|
|
2694
|
+
}, persisted);
|
|
2252
2695
|
}
|
|
2253
2696
|
return getRecommendPipelineRunTool({ args });
|
|
2254
2697
|
}
|
|
@@ -2276,15 +2719,11 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2276
2719
|
} catch {
|
|
2277
2720
|
const persisted = readRecommendRunState(runId);
|
|
2278
2721
|
if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
|
|
2279
|
-
return {
|
|
2722
|
+
return attachPersistedCdpEvidence({
|
|
2280
2723
|
status: "CANCEL_IGNORED",
|
|
2281
2724
|
run: compactRecommendRunForStatus(persisted),
|
|
2282
|
-
message: "目标任务已结束,无需取消。"
|
|
2283
|
-
|
|
2284
|
-
method_summary: {},
|
|
2285
|
-
method_log: [],
|
|
2286
|
-
chrome: null
|
|
2287
|
-
};
|
|
2725
|
+
message: "目标任务已结束,无需取消。"
|
|
2726
|
+
}, persisted);
|
|
2288
2727
|
}
|
|
2289
2728
|
const cancelMessage = "已收到取消请求,将由 detached worker 在下一个安全边界停止。";
|
|
2290
2729
|
const patched = patchPersistedRecommendRunControl(runId, {
|
|
@@ -2296,7 +2735,7 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2296
2735
|
message: cancelMessage
|
|
2297
2736
|
});
|
|
2298
2737
|
if (patched) {
|
|
2299
|
-
return {
|
|
2738
|
+
return attachPersistedCdpEvidence({
|
|
2300
2739
|
status: "CANCEL_REQUESTED",
|
|
2301
2740
|
run: compactRecommendRunForStatus(patched),
|
|
2302
2741
|
message: cancelMessage,
|
|
@@ -2304,12 +2743,8 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
|
|
|
2304
2743
|
source: "disk",
|
|
2305
2744
|
active_control_available: false,
|
|
2306
2745
|
detached_control_requested: true
|
|
2307
|
-
}
|
|
2308
|
-
|
|
2309
|
-
method_summary: {},
|
|
2310
|
-
method_log: [],
|
|
2311
|
-
chrome: null
|
|
2312
|
-
};
|
|
2746
|
+
}
|
|
2747
|
+
}, patched);
|
|
2313
2748
|
}
|
|
2314
2749
|
return getRecommendPipelineRunTool({ args });
|
|
2315
2750
|
}
|