@reconcrap/boss-recommend-mcp 2.1.22 → 2.1.23

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.
@@ -1,18 +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
- getMainFrameUrl,
12
- isBossLoginUrl,
13
- waitForMainFrameUrl,
14
- sleep
15
- } 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";
16
17
  import {
17
18
  RUN_STATUS_CANCELING,
18
19
  RUN_STATUS_CANCELED,
@@ -277,13 +278,22 @@ function normalizeScreeningModeArg(args = {}) {
277
278
  : "llm";
278
279
  }
279
280
 
280
- function collectRecommendDebugTestOptions(args = {}, normalized = {}) {
281
- const reasons = [];
281
+ function collectRecommendDebugTestOptions(args = {}, normalized = {}) {
282
+ const reasons = [];
282
283
  if (normalizeScreeningModeArg(args) === "deterministic") reasons.push("deterministic_screening");
283
284
  if (args.allow_card_only_screening === true) reasons.push("allow_card_only_screening");
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
- if (args.filter_enabled === false) reasons.push("filter_enabled=false");
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");
@@ -303,21 +313,39 @@ function resolveRecommendDetailLimit(args = {}, normalized = {}) {
303
313
  return requested;
304
314
  }
305
315
 
306
- function methodSummary(methodLog = []) {
307
- const summary = {};
308
- for (const entry of methodLog || []) {
309
- summary[entry.method] = (summary[entry.method] || 0) + 1;
310
- }
311
- return summary;
312
- }
313
-
314
- function compactMethodLogForStatus(methodLog = []) {
315
- if (!Array.isArray(methodLog)) return [];
316
- return methodLog.slice(-STATUS_METHOD_LOG_TAIL_LIMIT).map((entry) => ({
317
- method: normalizeText(entry?.method || entry || ""),
318
- at: normalizeText(entry?.at || "")
319
- }));
320
- }
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
+ function compactMethodLogForStatus(methodLog = []) {
340
+ if (!Array.isArray(methodLog)) return [];
341
+ return methodLog
342
+ .map((entry) => ({
343
+ method: compactCdpMethodName(entry?.method || entry || ""),
344
+ at: compactCdpMethodTimestamp(entry?.at || "")
345
+ }))
346
+ .filter((entry) => Boolean(entry.method))
347
+ .slice(-STATUS_METHOD_LOG_TAIL_LIMIT);
348
+ }
321
349
 
322
350
  function clonePlain(value, fallback = null) {
323
351
  try {
@@ -331,10 +359,130 @@ function plainRecord(value) {
331
359
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
332
360
  }
333
361
 
334
- function nonEmptyRecord(value) {
335
- const record = plainRecord(value);
336
- return Object.keys(record).length ? record : null;
337
- }
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
+ }
338
486
 
339
487
  function normalizeRunId(runId) {
340
488
  const normalized = normalizeText(runId);
@@ -506,17 +654,28 @@ function normalizeLegacyProgress(progress = {}, summary = null) {
506
654
  : Number.isInteger(summary?.passed)
507
655
  ? summary.passed
508
656
  : 0;
509
- return {
510
- ...progress,
657
+ const normalized = {
658
+ ...progress,
511
659
  processed,
512
660
  inspected: processed,
513
661
  screened,
514
662
  passed,
515
663
  skipped: Number.isInteger(progress.skipped) ? progress.skipped : Math.max(processed - passed, 0),
516
- greet_count: Number.isInteger(progress.greet_count) ? progress.greet_count : 0,
517
- post_action_clicked: Number.isInteger(progress.post_action_clicked) ? progress.post_action_clicked : 0
518
- };
519
- }
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
+ if (Object.prototype.hasOwnProperty.call(normalized, "list_read_stale_diagnostics")) {
673
+ normalized.list_read_stale_diagnostics = compactListReadStaleDiagnosticsForStatus(
674
+ normalized.list_read_stale_diagnostics
675
+ );
676
+ }
677
+ return normalized;
678
+ }
520
679
 
521
680
  const STATUS_COUNT_KEYS = [
522
681
  "processed",
@@ -544,11 +703,73 @@ function compactPositiveInteger(value, fallback = null) {
544
703
  return Number.isInteger(value) && value >= 0 ? value : fallback;
545
704
  }
546
705
 
547
- function compactSmallRecord(value, fallback = null) {
706
+ function compactSmallRecord(value, fallback = null) {
548
707
  const record = plainRecord(value);
549
708
  if (!Object.keys(record).length) return fallback;
550
- return clonePlain(record, fallback);
551
- }
709
+ return clonePlain(record, fallback);
710
+ }
711
+
712
+ function compactListReadStaleDiagnosticForStatus(value) {
713
+ const source = plainRecord(value);
714
+ if (!Object.keys(source).length) return null;
715
+ const compact = {};
716
+ for (const key of ["code", "message", "phase", "cdp_method", "cdp_at", "recovery_mode"]) {
717
+ const text = normalizeText(source[key] || "");
718
+ if (text) compact[key] = text.slice(0, key === "message" ? 500 : 200);
719
+ }
720
+ for (const key of ["cdp_node_id", "cdp_backend_node_id", "attempt"]) {
721
+ if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
722
+ }
723
+ for (const key of ["exhausted", "recovery_applied", "recovered"]) {
724
+ if (typeof source[key] === "boolean") compact[key] = source[key];
725
+ }
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
+ }
730
+ if (Array.isArray(source.cdp_param_keys)) {
731
+ compact.cdp_param_keys = source.cdp_param_keys
732
+ .map((key) => normalizeText(key))
733
+ .filter((key) => /^[A-Za-z][A-Za-z0-9_]*$/.test(key))
734
+ .slice(0, 20);
735
+ }
736
+ return Object.keys(compact).length ? compact : null;
737
+ }
738
+
739
+ function compactListReadStaleDiagnosticsForStatus(value) {
740
+ if (!Array.isArray(value)) return [];
741
+ return value
742
+ .map((item) => compactListReadStaleDiagnosticForStatus(item))
743
+ .filter(Boolean)
744
+ .slice(-12);
745
+ }
746
+
747
+ function compactListReadStaleCheckpointEvent(value) {
748
+ const source = plainRecord(value);
749
+ if (!Object.keys(source).length) return null;
750
+ const compact = {};
751
+ const diagnostic = compactListReadStaleDiagnosticForStatus(source.diagnostic || source.trigger);
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"]) {
756
+ if (Number.isInteger(source[key]) && source[key] >= 0) compact[key] = source[key];
757
+ }
758
+ if (source.recovery_error) {
759
+ const recoveryError = compactListReadStaleDiagnosticForStatus(source.recovery_error);
760
+ if (recoveryError) compact.recovery_error = recoveryError;
761
+ }
762
+ if (source.candidate_list) {
763
+ const candidateList = plainRecord(source.candidate_list);
764
+ compact.candidate_list = {};
765
+ for (const key of ["seen_count", "queued_count", "processed_count", "read_error_count", "scroll_count"]) {
766
+ if (Number.isInteger(candidateList[key]) && candidateList[key] >= 0) {
767
+ compact.candidate_list[key] = candidateList[key];
768
+ }
769
+ }
770
+ }
771
+ return Object.keys(compact).length ? compact : null;
772
+ }
552
773
 
553
774
  function compactRecommendSummaryForStatus(summary) {
554
775
  if (!summary || typeof summary !== "object" || Array.isArray(summary)) return null;
@@ -596,7 +817,7 @@ function compactRecommendSummaryForStatus(summary) {
596
817
  restLevel: normalizeText(summary.human_behavior.restLevel || summary.human_behavior.rest_level || "")
597
818
  };
598
819
  }
599
- if (summary.human_rest) {
820
+ if (summary.human_rest) {
600
821
  const humanRest = plainRecord(summary.human_rest);
601
822
  compact.human_rest = {
602
823
  enabled: humanRest.enabled === true,
@@ -604,9 +825,25 @@ function compactRecommendSummaryForStatus(summary) {
604
825
  rest_count: compactPositiveInteger(humanRest.rest_count ?? humanRest.count, null),
605
826
  total_pause_ms: compactPositiveInteger(humanRest.total_pause_ms ?? humanRest.pause_ms, null)
606
827
  };
607
- }
608
- return compact;
609
- }
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;
843
+ const staleDiagnostics = compactListReadStaleDiagnosticsForStatus(summary.list_read_stale_diagnostics);
844
+ if (staleDiagnostics.length) compact.list_read_stale_diagnostics = staleDiagnostics;
845
+ return compact;
846
+ }
610
847
 
611
848
  function compactRecommendCheckpointForStatus(checkpoint) {
612
849
  if (!checkpoint || typeof checkpoint !== "object" || Array.isArray(checkpoint)) return {};
@@ -619,11 +856,21 @@ function compactRecommendCheckpointForStatus(checkpoint) {
619
856
  } else if (Number.isInteger(checkpoint.results_count)) {
620
857
  compact.results_count = checkpoint.results_count;
621
858
  }
622
- for (const key of STATUS_COUNT_KEYS) {
623
- if (Number.isInteger(checkpoint[key])) compact[key] = checkpoint[key];
624
- }
625
- return compact;
626
- }
859
+ for (const key of STATUS_COUNT_KEYS) {
860
+ if (Number.isInteger(checkpoint[key])) compact[key] = checkpoint[key];
861
+ }
862
+ 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
+ ]) {
869
+ const event = compactListReadStaleCheckpointEvent(checkpoint[key]);
870
+ if (event) compact[key] = event;
871
+ }
872
+ return compact;
873
+ }
627
874
 
628
875
  function compactRecommendResultForStatus(result) {
629
876
  if (!result || typeof result !== "object" || Array.isArray(result)) return result || null;
@@ -1021,12 +1268,16 @@ function persistRecommendRunSnapshot(snapshot, {
1021
1268
  const artifacts = getRecommendRunArtifacts(normalized.run_id);
1022
1269
  if (!artifacts) return normalized;
1023
1270
  const existing = readJsonFile(artifacts.run_state_path);
1024
- normalized.control = mergePersistedControlRequest(normalized, existing);
1025
- normalized = coerceCanceledTerminalSnapshot(normalized, existing);
1026
- if (persistActiveCheckpoint) {
1027
- persistRecommendCheckpointSnapshot(snapshot);
1028
- }
1029
- const payload = {
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 = {
1030
1281
  run_id: normalized.run_id,
1031
1282
  mode: normalized.mode,
1032
1283
  state: normalized.state,
@@ -1042,12 +1293,14 @@ function persistRecommendRunSnapshot(snapshot, {
1042
1293
  context: normalized.context,
1043
1294
  control: normalized.control,
1044
1295
  resume: normalized.resume,
1045
- error: normalized.error,
1046
- recovery: normalized.recovery,
1047
- result: normalized.result,
1048
- summary: normalized.summary,
1049
- artifacts: normalized.artifacts
1050
- };
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
+ };
1051
1304
  writeJsonAtomic(artifacts.run_state_path, payload);
1052
1305
  return normalized;
1053
1306
  }
@@ -1120,19 +1373,18 @@ function persistRecommendLifecycleSnapshot(snapshot, event = {}) {
1120
1373
  });
1121
1374
  }
1122
1375
 
1123
- function attachMethodEvidence(payload, runId) {
1124
- const meta = getRecommendRunMeta(runId);
1125
- const methodLog = meta.methodLog || [];
1126
- assertNoForbiddenCdpCalls(methodLog);
1127
- return {
1128
- ...payload,
1129
- runtime_evaluate_used: false,
1130
- method_summary: methodSummary(methodLog),
1131
- method_log: compactMethodLogForStatus(methodLog),
1132
- method_log_total: Array.isArray(methodLog) ? methodLog.length : 0,
1133
- chrome: meta.chrome || null
1134
- };
1135
- }
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
+ }
1136
1388
 
1137
1389
  function compactRecommendJobListOption(option, index) {
1138
1390
  const label = normalizeText(option?.label);
@@ -1819,10 +2071,23 @@ function getRunOptions(args, parsed, normalized, session, configResolution = nul
1819
2071
  ) || "low",
1820
2072
  imageOutputDir: resolveBossConfiguredOutputDir("", getRunsDir()),
1821
2073
  humanRestEnabled: humanBehavior.restEnabled,
1822
- humanBehavior,
1823
- skipRecentColleagueContacted: normalized.skipRecentColleagueContacted,
1824
- colleagueContactWindowDays: normalized.colleagueContactWindowDays,
1825
- name: "mcp-recommend-pipeline-run",
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",
1826
2091
  parsed
1827
2092
  };
1828
2093
  }
@@ -2114,22 +2379,19 @@ export function getRecommendPipelineRunTool({ args = {} } = {}) {
2114
2379
  run: compactRecommendRunForStatus(normalizedRun)
2115
2380
  }, runId);
2116
2381
  } catch {
2117
- const persisted = readRecommendRunState(runId);
2118
- if (persisted) {
2119
- const reconciled = compactRecommendRunForStatus(reconcilePersistedRecommendRunIfNeeded(persisted));
2120
- return {
2121
- status: "RUN_STATUS",
2122
- run: reconciled,
2123
- persistence: {
2124
- source: "disk",
2125
- active_control_available: false,
2126
- stale_process_reconciled: reconciled?.state !== persisted.state
2127
- },
2128
- runtime_evaluate_used: false,
2129
- method_summary: {},
2130
- method_log: [],
2131
- chrome: null
2132
- };
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);
2133
2395
  }
2134
2396
  return {
2135
2397
  status: "FAILED",
@@ -2170,17 +2432,13 @@ export function pauseRecommendPipelineRunTool({ args = {} } = {}) {
2170
2432
  message: "暂停请求已接收,将在当前候选人处理完成后进入 paused。"
2171
2433
  }, runId);
2172
2434
  } catch {
2173
- const persisted = readRecommendRunState(runId);
2174
- if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
2175
- return {
2176
- status: "PAUSE_IGNORED",
2177
- run: compactRecommendRunForStatus(persisted),
2178
- message: "目标任务已结束,无需暂停。",
2179
- runtime_evaluate_used: false,
2180
- method_summary: {},
2181
- method_log: [],
2182
- chrome: null
2183
- };
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);
2184
2442
  }
2185
2443
  return getRecommendPipelineRunTool({ args });
2186
2444
  }
@@ -2228,11 +2486,11 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
2228
2486
  message: "已恢复 Recommend run,请使用 get_recommend_pipeline_run 按需轮询。"
2229
2487
  }, runId);
2230
2488
  } catch {
2231
- const persisted = readRecommendRunState(runId);
2232
- if (persisted) {
2233
- return {
2234
- status: "FAILED",
2235
- error: {
2489
+ const persisted = readRecommendRunState(runId);
2490
+ if (persisted) {
2491
+ return attachPersistedCdpEvidence({
2492
+ status: "FAILED",
2493
+ error: {
2236
2494
  code: TERMINAL_STATUSES.has(persisted.state) ? "RUN_ALREADY_TERMINATED" : "RUN_NOT_ACTIVE",
2237
2495
  message: TERMINAL_STATUSES.has(persisted.state)
2238
2496
  ? "目标任务已结束,无法继续。"
@@ -2240,15 +2498,11 @@ export function resumeRecommendPipelineRunTool({ args = {} } = {}) {
2240
2498
  retryable: !TERMINAL_STATUSES.has(persisted.state)
2241
2499
  },
2242
2500
  run: compactRecommendRunForStatus(persisted),
2243
- persistence: {
2244
- source: "disk",
2245
- active_control_available: false
2246
- },
2247
- runtime_evaluate_used: false,
2248
- method_summary: {},
2249
- method_log: [],
2250
- chrome: null
2251
- };
2501
+ persistence: {
2502
+ source: "disk",
2503
+ active_control_available: false
2504
+ }
2505
+ }, persisted);
2252
2506
  }
2253
2507
  return getRecommendPipelineRunTool({ args });
2254
2508
  }
@@ -2274,17 +2528,13 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
2274
2528
  message: "已收到取消请求,将在当前候选人处理完成后安全停止。"
2275
2529
  }, runId);
2276
2530
  } catch {
2277
- const persisted = readRecommendRunState(runId);
2278
- if (persisted && TERMINAL_STATUSES.has(persisted.state)) {
2279
- return {
2280
- status: "CANCEL_IGNORED",
2281
- run: compactRecommendRunForStatus(persisted),
2282
- message: "目标任务已结束,无需取消。",
2283
- runtime_evaluate_used: false,
2284
- method_summary: {},
2285
- method_log: [],
2286
- chrome: null
2287
- };
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);
2288
2538
  }
2289
2539
  const cancelMessage = "已收到取消请求,将由 detached worker 在下一个安全边界停止。";
2290
2540
  const patched = patchPersistedRecommendRunControl(runId, {
@@ -2294,22 +2544,18 @@ export function cancelRecommendPipelineRunTool({ args = {} } = {}) {
2294
2544
  cancel_requested: true
2295
2545
  }, {
2296
2546
  message: cancelMessage
2297
- });
2298
- if (patched) {
2299
- return {
2300
- status: "CANCEL_REQUESTED",
2301
- run: compactRecommendRunForStatus(patched),
2547
+ });
2548
+ if (patched) {
2549
+ return attachPersistedCdpEvidence({
2550
+ status: "CANCEL_REQUESTED",
2551
+ run: compactRecommendRunForStatus(patched),
2302
2552
  message: cancelMessage,
2303
2553
  persistence: {
2304
2554
  source: "disk",
2305
- active_control_available: false,
2306
- detached_control_requested: true
2307
- },
2308
- runtime_evaluate_used: false,
2309
- method_summary: {},
2310
- method_log: [],
2311
- chrome: null
2312
- };
2555
+ active_control_available: false,
2556
+ detached_control_requested: true
2557
+ }
2558
+ }, patched);
2313
2559
  }
2314
2560
  return getRecommendPipelineRunTool({ args });
2315
2561
  }