@reconcrap/boss-recommend-mcp 2.0.38 → 2.0.39

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.
@@ -92,6 +92,63 @@ function refreshFailureReason(method = "") {
92
92
  return method === "page_navigate" ? "page_navigate_failed" : "page_reload_failed";
93
93
  }
94
94
 
95
+ export function isRetryableRecommendFilterReapplyError(error) {
96
+ const message = String(error?.message || error || "");
97
+ return /Recommend filter panel did not open|Recommend filter trigger was not found|Recommend filter confirm button was not found|No matching recommend filter option/i.test(message);
98
+ }
99
+
100
+ function compactFilterReapplyError(error) {
101
+ return error?.message || String(error || "Recommend filter reapply failed");
102
+ }
103
+
104
+ async function selectAndConfirmRefreshFilter(client, rootState, filterOptions, {
105
+ maxAttempts = 3,
106
+ retryDelayMs = 1500
107
+ } = {}) {
108
+ const attempts = [];
109
+ let currentRootState = rootState;
110
+ let lastError = null;
111
+
112
+ for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
113
+ try {
114
+ const filter = await selectAndConfirmFirstSafeFilter(
115
+ client,
116
+ currentRootState.iframe.documentNodeId,
117
+ filterOptions
118
+ );
119
+ attempts.push({
120
+ ok: true,
121
+ method: "filter_reapply",
122
+ attempt
123
+ });
124
+ return {
125
+ filter,
126
+ root_state: currentRootState,
127
+ attempts
128
+ };
129
+ } catch (error) {
130
+ lastError = error;
131
+ attempts.push({
132
+ ok: false,
133
+ method: "filter_reapply",
134
+ reason: "filter_reapply_failed",
135
+ error: compactFilterReapplyError(error),
136
+ attempt
137
+ });
138
+ if (attempt >= maxAttempts || !isRetryableRecommendFilterReapplyError(error)) {
139
+ break;
140
+ }
141
+ if (retryDelayMs > 0) await sleep(retryDelayMs);
142
+ currentRootState = await getRecommendRoots(client);
143
+ }
144
+ }
145
+
146
+ const wrapped = new Error(compactFilterReapplyError(lastError));
147
+ wrapped.cause = lastError;
148
+ wrapped.filter_reapply_attempts = attempts;
149
+ throw wrapped;
150
+ }
151
+
95
152
  async function applyRefreshMethod(client, method, {
96
153
  jobLabel = "",
97
154
  pageScope = "recommend",
@@ -107,6 +164,7 @@ async function applyRefreshMethod(client, method, {
107
164
  let jobSelection = null;
108
165
  let pageScopeResult = null;
109
166
  let filterResult = null;
167
+ let filterReapplyAttempts = [];
110
168
  try {
111
169
  if (method === "page_navigate") {
112
170
  await client.Page.navigate({ url: targetUrl || RECOMMEND_TARGET_URL });
@@ -145,11 +203,17 @@ async function applyRefreshMethod(client, method, {
145
203
  throw new Error(`Recommend page scope was not selected after refresh reload: ${pageScopeResult.reason || pageScope}`);
146
204
  }
147
205
  currentRootState = await getRecommendRoots(client);
148
- filterResult = await selectAndConfirmFirstSafeFilter(
206
+ const filterSelection = await selectAndConfirmRefreshFilter(
149
207
  client,
150
- currentRootState.iframe.documentNodeId,
151
- buildRecommendFilterSelectionOptions(filter, { forceRecentNotView })
208
+ currentRootState,
209
+ buildRecommendFilterSelectionOptions(filter, { forceRecentNotView }),
210
+ {
211
+ retryDelayMs: Math.max(1200, Math.min(5000, Math.floor((reloadSettleMs || 8000) / 2)))
212
+ }
152
213
  );
214
+ filterResult = filterSelection.filter;
215
+ filterReapplyAttempts = filterSelection.attempts;
216
+ currentRootState = await getRecommendRoots(client);
153
217
  const cardNodeIds = await waitForRecommendCardNodeIds(client, currentRootState.iframe.documentNodeId, {
154
218
  timeoutMs: cardTimeoutMs,
155
219
  intervalMs: 500
@@ -164,6 +228,7 @@ async function applyRefreshMethod(client, method, {
164
228
  job_selection: jobSelection,
165
229
  page_scope: pageScopeResult,
166
230
  filter: filterResult,
231
+ filter_reapply_attempts: filterReapplyAttempts,
167
232
  card_count: cardNodeIds.length,
168
233
  root_state: currentRootState,
169
234
  forced_recent_not_view: forceRecentNotView,
@@ -179,6 +244,7 @@ async function applyRefreshMethod(client, method, {
179
244
  job_selection: jobSelection,
180
245
  page_scope: pageScopeResult,
181
246
  filter: filterResult,
247
+ filter_reapply_attempts: error?.filter_reapply_attempts || filterReapplyAttempts,
182
248
  card_count: 0,
183
249
  root_state: currentRootState,
184
250
  forced_recent_not_view: forceRecentNotView,
@@ -229,11 +295,16 @@ export async function refreshRecommendListAtEnd(client, {
229
295
  throw new Error(`Recommend page scope was not selected after end refresh: ${pageScopeResult.reason || pageScope}`);
230
296
  }
231
297
  currentRootState = await getRecommendRoots(client);
232
- const filterResult = await selectAndConfirmFirstSafeFilter(
298
+ const filterSelection = await selectAndConfirmRefreshFilter(
233
299
  client,
234
- currentRootState.iframe.documentNodeId,
235
- buildRecommendFilterSelectionOptions(filter, { forceRecentNotView })
300
+ currentRootState,
301
+ buildRecommendFilterSelectionOptions(filter, { forceRecentNotView }),
302
+ {
303
+ retryDelayMs: Math.max(1200, Math.min(5000, Math.floor((buttonSettleMs || 8000) / 2)))
304
+ }
236
305
  );
306
+ const filterResult = filterSelection.filter;
307
+ currentRootState = await getRecommendRoots(client);
237
308
  const cardNodeIds = await waitForRecommendCardNodeIds(client, currentRootState.iframe.documentNodeId, {
238
309
  timeoutMs: cardTimeoutMs,
239
310
  intervalMs: 500
@@ -244,6 +315,7 @@ export async function refreshRecommendListAtEnd(client, {
244
315
  attempts,
245
316
  page_scope: pageScopeResult,
246
317
  filter: filterResult,
318
+ filter_reapply_attempts: filterSelection.attempts,
247
319
  card_count: cardNodeIds.length,
248
320
  root_state: currentRootState,
249
321
  forced_recent_not_view: forceRecentNotView