@reconcrap/boss-recommend-mcp 2.0.13 → 2.0.14
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
package/src/domains/chat/jobs.js
CHANGED
|
@@ -223,6 +223,15 @@ function matchJobOption(option, jobLabel = "") {
|
|
|
223
223
|
));
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
function activeMatchingJobOption(options = [], jobLabel = "") {
|
|
227
|
+
return (options || []).find((option) => option.active && matchJobOption(option, jobLabel)) || null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function selectedLabelMatches(label = "", jobLabel = "") {
|
|
231
|
+
const normalized = normalizeJobText(label);
|
|
232
|
+
return Boolean(normalized && matchJobOption({ label: normalized, value: normalized, title: normalized }, jobLabel));
|
|
233
|
+
}
|
|
234
|
+
|
|
226
235
|
async function clickFirstVisible(client, rootNodeId, selectors = []) {
|
|
227
236
|
for (const selector of selectors) {
|
|
228
237
|
const nodeIds = await safeQuerySelectorAll(client, rootNodeId, selector);
|
|
@@ -247,6 +256,62 @@ async function clickFirstVisible(client, rootNodeId, selectors = []) {
|
|
|
247
256
|
};
|
|
248
257
|
}
|
|
249
258
|
|
|
259
|
+
async function waitForChatJobOptions(client, rootNodeId, {
|
|
260
|
+
timeoutMs = 12000,
|
|
261
|
+
intervalMs = 300,
|
|
262
|
+
requireVisible = false
|
|
263
|
+
} = {}) {
|
|
264
|
+
const started = Date.now();
|
|
265
|
+
let latest = null;
|
|
266
|
+
while (Date.now() - started <= timeoutMs) {
|
|
267
|
+
const currentRootNodeId = await freshTopRootNodeId(client, rootNodeId);
|
|
268
|
+
latest = await readChatJobOptions(client, currentRootNodeId, {
|
|
269
|
+
timeoutMs: Math.min(intervalMs, 300),
|
|
270
|
+
intervalMs
|
|
271
|
+
});
|
|
272
|
+
const options = latest.job_options || [];
|
|
273
|
+
if (options.length && (!requireVisible || options.some((option) => option.visible))) {
|
|
274
|
+
return latest;
|
|
275
|
+
}
|
|
276
|
+
await sleep(intervalMs);
|
|
277
|
+
}
|
|
278
|
+
return latest || {
|
|
279
|
+
selector: "",
|
|
280
|
+
source: "chat-job-list",
|
|
281
|
+
selected_label: "",
|
|
282
|
+
job_options: []
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
async function waitForSelectedChatJob(client, rootNodeId, jobLabel = "", {
|
|
287
|
+
timeoutMs = 5000,
|
|
288
|
+
intervalMs = 300
|
|
289
|
+
} = {}) {
|
|
290
|
+
const started = Date.now();
|
|
291
|
+
let latest = null;
|
|
292
|
+
while (Date.now() - started <= timeoutMs) {
|
|
293
|
+
const currentRootNodeId = await freshTopRootNodeId(client, rootNodeId);
|
|
294
|
+
latest = await readChatJobOptions(client, currentRootNodeId, {
|
|
295
|
+
timeoutMs: Math.min(intervalMs, 300),
|
|
296
|
+
intervalMs
|
|
297
|
+
});
|
|
298
|
+
if (
|
|
299
|
+
selectedLabelMatches(latest.selected_label, jobLabel)
|
|
300
|
+
|| activeMatchingJobOption(latest.job_options || [], jobLabel)
|
|
301
|
+
) {
|
|
302
|
+
return {
|
|
303
|
+
verified: true,
|
|
304
|
+
result: latest
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
await sleep(intervalMs);
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
verified: false,
|
|
311
|
+
result: latest
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
250
315
|
export async function selectChatJob(client, rootNodeId, {
|
|
251
316
|
jobLabel = "",
|
|
252
317
|
timeoutMs = 12000,
|
|
@@ -267,14 +332,34 @@ export async function selectChatJob(client, rootNodeId, {
|
|
|
267
332
|
intervalMs
|
|
268
333
|
});
|
|
269
334
|
let matched = (optionsResult.job_options || []).find((option) => matchJobOption(option, requested)) || null;
|
|
335
|
+
if (
|
|
336
|
+
matched
|
|
337
|
+
&& (
|
|
338
|
+
matched.active
|
|
339
|
+
|| selectedLabelMatches(optionsResult.selected_label, matched.label)
|
|
340
|
+
|| selectedLabelMatches(optionsResult.selected_label, requested)
|
|
341
|
+
)
|
|
342
|
+
) {
|
|
343
|
+
return {
|
|
344
|
+
selected: true,
|
|
345
|
+
verified: true,
|
|
346
|
+
already_current: true,
|
|
347
|
+
requested,
|
|
348
|
+
selected_option: matched,
|
|
349
|
+
options: optionsResult.job_options || [],
|
|
350
|
+
selected_label: optionsResult.selected_label || matched.label
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
|
|
270
354
|
if (!matched || !matched.visible) {
|
|
271
355
|
const triggerRootNodeId = await freshTopRootNodeId(client, currentRootNodeId);
|
|
272
356
|
const trigger = await clickFirstVisible(client, triggerRootNodeId, CHAT_JOB_TRIGGER_SELECTORS);
|
|
273
357
|
if (settleMs > 0) await sleep(settleMs);
|
|
274
358
|
currentRootNodeId = await freshTopRootNodeId(client, triggerRootNodeId);
|
|
275
|
-
optionsResult = await
|
|
359
|
+
optionsResult = await waitForChatJobOptions(client, currentRootNodeId, {
|
|
276
360
|
timeoutMs,
|
|
277
|
-
intervalMs
|
|
361
|
+
intervalMs,
|
|
362
|
+
requireVisible: true
|
|
278
363
|
});
|
|
279
364
|
matched = (optionsResult.job_options || []).find((option) => matchJobOption(option, requested)) || null;
|
|
280
365
|
if (!matched || !matched.visible) {
|
|
@@ -292,6 +377,7 @@ export async function selectChatJob(client, rootNodeId, {
|
|
|
292
377
|
if (matched.active || normalizeJobText(optionsResult.selected_label).toLowerCase() === normalizeJobText(matched.label).toLowerCase()) {
|
|
293
378
|
return {
|
|
294
379
|
selected: true,
|
|
380
|
+
verified: true,
|
|
295
381
|
already_current: true,
|
|
296
382
|
requested,
|
|
297
383
|
selected_option: matched,
|
|
@@ -310,22 +396,27 @@ export async function selectChatJob(client, rootNodeId, {
|
|
|
310
396
|
if (settleMs > 0) await sleep(settleMs);
|
|
311
397
|
|
|
312
398
|
const afterRootNodeId = await freshTopRootNodeId(client, currentRootNodeId);
|
|
313
|
-
const
|
|
314
|
-
timeoutMs: Math.min(timeoutMs,
|
|
399
|
+
const verification = await waitForSelectedChatJob(client, afterRootNodeId, matched.label, {
|
|
400
|
+
timeoutMs: Math.min(timeoutMs, 5000),
|
|
315
401
|
intervalMs
|
|
316
402
|
});
|
|
403
|
+
const after = verification.result || {
|
|
404
|
+
selected_label: "",
|
|
405
|
+
job_options: []
|
|
406
|
+
};
|
|
317
407
|
const afterMatch = (after.job_options || []).find((option) => matchJobOption(option, matched.label)) || matched;
|
|
318
|
-
const selectedLabel = normalizeJobText(after.selected_label ||
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
: true;
|
|
408
|
+
const selectedLabel = normalizeJobText(after.selected_label || "");
|
|
409
|
+
const activeMatch = activeMatchingJobOption(after.job_options || [], matched.label);
|
|
410
|
+
const verified = Boolean(verification.verified || selectedLabelMatches(selectedLabel, matched.label) || activeMatch);
|
|
322
411
|
|
|
323
412
|
return {
|
|
324
|
-
selected:
|
|
413
|
+
selected: verified,
|
|
325
414
|
verified,
|
|
326
415
|
already_current: false,
|
|
416
|
+
reason: verified ? "verified" : "job_selection_not_verified",
|
|
327
417
|
requested,
|
|
328
418
|
selected_option: afterMatch,
|
|
419
|
+
active_option: activeMatch,
|
|
329
420
|
options: after.job_options || optionsResult.job_options || [],
|
|
330
421
|
selected_label: selectedLabel,
|
|
331
422
|
before: optionsResult,
|
|
@@ -306,6 +306,9 @@ async function setupChatRunContext(client, {
|
|
|
306
306
|
if (normalizeText(job) && !jobSelection.selected) {
|
|
307
307
|
throw new Error(`Chat job selection failed: ${jobSelection.reason || "unknown"}`);
|
|
308
308
|
}
|
|
309
|
+
if (normalizeText(job) && jobSelection.verified !== true) {
|
|
310
|
+
throw new Error(`Chat job selection was not verified: requested=${jobSelection.requested || job}; selected=${jobSelection.selected_label || "unknown"}`);
|
|
311
|
+
}
|
|
309
312
|
rootState = await getChatRoots(client);
|
|
310
313
|
if (ensureViewport) {
|
|
311
314
|
rootState = await ensureViewport(rootState, "context_job");
|