@cutleryapp/agent 1.0.8 → 1.0.10
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/dist/cli.js +18 -1
- package/dist/mcp-executor.js +29 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -417,7 +417,24 @@ function runConnect(opts) {
|
|
|
417
417
|
}
|
|
418
418
|
if (message.type === "registered") {
|
|
419
419
|
registered = true;
|
|
420
|
-
|
|
420
|
+
// Render the resolved plan / cap / utilisation when the server
|
|
421
|
+
// provides them (added in server.ts >= today). Older servers send
|
|
422
|
+
// only { type, agentName, timestamp } — the optional chains below
|
|
423
|
+
// make the line gracefully degrade to the previous one-liner.
|
|
424
|
+
const planName = message?.plan?.name;
|
|
425
|
+
const cap = typeof message?.cap === "number" ? message.cap : null;
|
|
426
|
+
const used = typeof message?.used === "number" ? message.used : null;
|
|
427
|
+
if (planName && cap !== null && used !== null) {
|
|
428
|
+
const fraction = cap === -1 ? "∞ agents allowed" : `${used}/${cap} agents used`;
|
|
429
|
+
log(chalk_1.default.green(`✓ Registration confirmed by server`) +
|
|
430
|
+
chalk_1.default.gray(` · ${planName} plan · ${fraction}`));
|
|
431
|
+
if (cap !== -1 && used >= cap) {
|
|
432
|
+
log(chalk_1.default.yellow(` ⚠ You're at your plan's concurrent-agent cap. Disconnect another agent or upgrade at ${message.upgradeUrl ?? "/pricing"}.`));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
log(chalk_1.default.green(`✓ Registration confirmed by server`));
|
|
437
|
+
}
|
|
421
438
|
opts.onRegistered?.();
|
|
422
439
|
}
|
|
423
440
|
else if (message.type === "evicted") {
|
package/dist/mcp-executor.js
CHANGED
|
@@ -77,11 +77,16 @@ class TestExecutor {
|
|
|
77
77
|
}
|
|
78
78
|
else if (lower.includes("click")) {
|
|
79
79
|
const labelMatch = raw.match(/click\s+(?:on\s+)?(?:the\s+)?"?([^"]+?)"?\s*(?:button|link|tab)?$/i);
|
|
80
|
-
|
|
80
|
+
let label = labelMatch?.[1]?.trim();
|
|
81
81
|
if (label) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
82
|
+
// Split "Add to cart under Sauce Labs Bike Light product" into target + scope
|
|
83
|
+
const scopeMatch = label.match(/^(.+?)\s+(?:under|inside|within|in the)\s+(.+)$/i);
|
|
84
|
+
const target = scopeMatch ? scopeMatch[1].trim() : label;
|
|
85
|
+
const scope = scopeMatch ? scopeMatch[2].trim() : null;
|
|
86
|
+
const nameRe = new RegExp(escapeRegex(target), 'i');
|
|
87
|
+
const clicked = scope
|
|
88
|
+
? await tryClickScoped(page, nameRe, target, scope)
|
|
89
|
+
: await tryClick(page, nameRe, target);
|
|
85
90
|
if (!clicked)
|
|
86
91
|
throw new Error(`Could not find clickable element: "${label}"`);
|
|
87
92
|
}
|
|
@@ -216,6 +221,26 @@ async function tryClick(page, nameRe, label) {
|
|
|
216
221
|
}
|
|
217
222
|
return false;
|
|
218
223
|
}
|
|
224
|
+
async function tryClickScoped(page, nameRe, target, scope) {
|
|
225
|
+
const FAST = 3000;
|
|
226
|
+
// Find a container that contains the scope text, then click the target inside it
|
|
227
|
+
const strategies = [
|
|
228
|
+
() => page.locator(`:has-text("${scope}")`).last().getByRole('button', { name: nameRe }).first().click({ timeout: FAST }),
|
|
229
|
+
() => page.locator(`:has-text("${scope}")`).last().getByRole('link', { name: nameRe }).first().click({ timeout: FAST }),
|
|
230
|
+
() => page.locator(`:has-text("${scope}")`).last().getByText(nameRe).first().click({ timeout: FAST }),
|
|
231
|
+
// Fallback: ignore scope and click anywhere
|
|
232
|
+
() => page.getByRole('button', { name: nameRe }).first().click({ timeout: FAST }),
|
|
233
|
+
() => page.getByText(nameRe).first().click({ timeout: FAST }),
|
|
234
|
+
];
|
|
235
|
+
for (const fn of strategies) {
|
|
236
|
+
try {
|
|
237
|
+
await fn();
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
catch { /* try next */ }
|
|
241
|
+
}
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
219
244
|
async function tryFill(page, label, value) {
|
|
220
245
|
const FAST = 1500;
|
|
221
246
|
const labelRe = new RegExp(escapeRegex(label), "i");
|