@reconcrap/boss-recommend-mcp 2.0.40 → 2.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -101,6 +101,91 @@ function compactFilterReapplyError(error) {
|
|
|
101
101
|
return error?.message || String(error || "Recommend filter reapply failed");
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
export function isRetryableRecommendJobSelectionError(error) {
|
|
105
|
+
const message = String(error?.message || error || "");
|
|
106
|
+
return /Recommend job trigger was not found|Recommend job dropdown did not mount options/i.test(message);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function compactJobSelectionAttempt({
|
|
110
|
+
ok = false,
|
|
111
|
+
attempt = 0,
|
|
112
|
+
iframeDocumentNodeId = 0,
|
|
113
|
+
error = null,
|
|
114
|
+
selection = null
|
|
115
|
+
} = {}) {
|
|
116
|
+
return {
|
|
117
|
+
ok: Boolean(ok),
|
|
118
|
+
method: "job_select",
|
|
119
|
+
reason: error ? "job_select_failed" : null,
|
|
120
|
+
error: error ? (error?.message || String(error)) : null,
|
|
121
|
+
attempt,
|
|
122
|
+
iframe_document_node_id: iframeDocumentNodeId || 0,
|
|
123
|
+
selected: Boolean(selection?.selected),
|
|
124
|
+
selection_reason: selection?.reason || null
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export async function selectRecommendJobWithRootRefresh(client, rootState, {
|
|
129
|
+
jobLabel = "",
|
|
130
|
+
settleMs = 6000,
|
|
131
|
+
dropdownTimeoutMs = 4000,
|
|
132
|
+
totalTimeoutMs = 30000,
|
|
133
|
+
retryDelayMs = 1000
|
|
134
|
+
} = {}) {
|
|
135
|
+
const started = Date.now();
|
|
136
|
+
const attempts = [];
|
|
137
|
+
let currentRootState = rootState || null;
|
|
138
|
+
let lastError = null;
|
|
139
|
+
let attempt = 0;
|
|
140
|
+
|
|
141
|
+
while (Date.now() - started <= totalTimeoutMs) {
|
|
142
|
+
attempt += 1;
|
|
143
|
+
if (!currentRootState?.iframe?.documentNodeId) {
|
|
144
|
+
currentRootState = await getRecommendRoots(client);
|
|
145
|
+
}
|
|
146
|
+
const iframeDocumentNodeId = currentRootState?.iframe?.documentNodeId || 0;
|
|
147
|
+
try {
|
|
148
|
+
const selection = await selectRecommendJob(client, iframeDocumentNodeId, {
|
|
149
|
+
jobLabel,
|
|
150
|
+
settleMs,
|
|
151
|
+
dropdownTimeoutMs
|
|
152
|
+
});
|
|
153
|
+
attempts.push(compactJobSelectionAttempt({
|
|
154
|
+
ok: true,
|
|
155
|
+
attempt,
|
|
156
|
+
iframeDocumentNodeId,
|
|
157
|
+
selection
|
|
158
|
+
}));
|
|
159
|
+
return {
|
|
160
|
+
job_selection: {
|
|
161
|
+
...selection,
|
|
162
|
+
refresh_attempts: attempts
|
|
163
|
+
},
|
|
164
|
+
root_state: currentRootState,
|
|
165
|
+
attempts
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
lastError = error;
|
|
169
|
+
attempts.push(compactJobSelectionAttempt({
|
|
170
|
+
ok: false,
|
|
171
|
+
attempt,
|
|
172
|
+
iframeDocumentNodeId,
|
|
173
|
+
error
|
|
174
|
+
}));
|
|
175
|
+
if (!isRetryableRecommendJobSelectionError(error) || Date.now() - started >= totalTimeoutMs) {
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
if (retryDelayMs > 0) await sleep(retryDelayMs);
|
|
179
|
+
currentRootState = await getRecommendRoots(client);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const wrapped = new Error(lastError?.message || "Recommend job selection failed after refresh reload");
|
|
184
|
+
wrapped.cause = lastError;
|
|
185
|
+
wrapped.job_selection_attempts = attempts;
|
|
186
|
+
throw wrapped;
|
|
187
|
+
}
|
|
188
|
+
|
|
104
189
|
async function selectAndConfirmRefreshFilter(client, rootState, filterOptions, {
|
|
105
190
|
maxAttempts = 3,
|
|
106
191
|
retryDelayMs = 1500
|
|
@@ -162,6 +247,7 @@ async function applyRefreshMethod(client, method, {
|
|
|
162
247
|
const started = Date.now();
|
|
163
248
|
let currentRootState = null;
|
|
164
249
|
let jobSelection = null;
|
|
250
|
+
let jobSelectionAttempts = [];
|
|
165
251
|
let pageScopeResult = null;
|
|
166
252
|
let filterResult = null;
|
|
167
253
|
let filterReapplyAttempts = [];
|
|
@@ -180,16 +266,19 @@ async function applyRefreshMethod(client, method, {
|
|
|
180
266
|
throw new Error("Recommend iframe was not ready after refresh reload");
|
|
181
267
|
}
|
|
182
268
|
if (jobLabel) {
|
|
183
|
-
const
|
|
184
|
-
jobSelection = await selectRecommendJob(client, currentRootState.iframe.documentNodeId, {
|
|
269
|
+
const jobSelectionResult = await selectRecommendJobWithRootRefresh(client, currentRootState, {
|
|
185
270
|
jobLabel,
|
|
186
271
|
settleMs: reloadSettleMs > 10000 ? 12000 : 6000,
|
|
187
|
-
dropdownTimeoutMs:
|
|
272
|
+
dropdownTimeoutMs: 4000,
|
|
273
|
+
totalTimeoutMs: reloadSettleMs > 10000 ? 45000 : 30000,
|
|
274
|
+
retryDelayMs: 1200
|
|
188
275
|
});
|
|
276
|
+
jobSelection = jobSelectionResult.job_selection;
|
|
277
|
+
jobSelectionAttempts = jobSelectionResult.attempts;
|
|
189
278
|
if (!jobSelection.selected) {
|
|
190
279
|
throw new Error(`Requested recommend job was not selected after refresh reload: ${jobSelection.reason}`);
|
|
191
280
|
}
|
|
192
|
-
currentRootState = await getRecommendRoots(client);
|
|
281
|
+
currentRootState = jobSelectionResult.root_state || await getRecommendRoots(client);
|
|
193
282
|
}
|
|
194
283
|
pageScopeResult = await selectRecommendPageScope(
|
|
195
284
|
client,
|
|
@@ -228,6 +317,7 @@ async function applyRefreshMethod(client, method, {
|
|
|
228
317
|
method,
|
|
229
318
|
target_url: method === "page_navigate" ? (targetUrl || RECOMMEND_TARGET_URL) : null,
|
|
230
319
|
job_selection: jobSelection,
|
|
320
|
+
job_selection_attempts: jobSelectionAttempts,
|
|
231
321
|
page_scope: pageScopeResult,
|
|
232
322
|
filter: filterResult,
|
|
233
323
|
filter_reapply_attempts: filterReapplyAttempts,
|
|
@@ -244,6 +334,7 @@ async function applyRefreshMethod(client, method, {
|
|
|
244
334
|
error: error?.message || String(error),
|
|
245
335
|
target_url: method === "page_navigate" ? (targetUrl || RECOMMEND_TARGET_URL) : null,
|
|
246
336
|
job_selection: jobSelection,
|
|
337
|
+
job_selection_attempts: error?.job_selection_attempts || jobSelectionAttempts,
|
|
247
338
|
page_scope: pageScopeResult,
|
|
248
339
|
filter: filterResult,
|
|
249
340
|
filter_reapply_attempts: error?.filter_reapply_attempts || filterReapplyAttempts,
|
|
@@ -379,6 +379,16 @@ function compactRefreshAttempt(refreshAttempt) {
|
|
|
379
379
|
error: attempt.error || null,
|
|
380
380
|
attempt: attempt.attempt || 0
|
|
381
381
|
})),
|
|
382
|
+
job_selection_attempts: (refreshAttempt.job_selection_attempts || []).map((attempt) => ({
|
|
383
|
+
ok: Boolean(attempt.ok),
|
|
384
|
+
method: attempt.method || "job_select",
|
|
385
|
+
reason: attempt.reason || null,
|
|
386
|
+
error: attempt.error || null,
|
|
387
|
+
attempt: attempt.attempt || 0,
|
|
388
|
+
iframe_document_node_id: attempt.iframe_document_node_id || 0,
|
|
389
|
+
selected: Boolean(attempt.selected),
|
|
390
|
+
selection_reason: attempt.selection_reason || null
|
|
391
|
+
})),
|
|
382
392
|
job_selection: compactJobSelection(refreshAttempt.job_selection),
|
|
383
393
|
page_scope: compactPageScopeSelection(refreshAttempt.page_scope),
|
|
384
394
|
filter: compactFilterResult(refreshAttempt.filter)
|