@gleanwork/mcp-server-tester 2.0.0-beta.1 → 2.0.0-beta.3
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/index.js +458 -66
- package/dist/fixtures/mcp.js +1 -1
- package/dist/fixtures/mcp.js.map +1 -1
- package/dist/index.cjs +7798 -7026
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -1
- package/dist/index.d.ts +71 -1
- package/dist/index.js +7806 -7035
- package/dist/index.js.map +1 -1
- package/package.json +4 -1
- package/scripts/cowork_linux.py +210 -0
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as path2 from 'path';
|
|
3
|
-
import path2__default, { resolve, join,
|
|
3
|
+
import path2__default, { resolve, join, dirname, basename, isAbsolute, posix, sep } from 'path';
|
|
4
4
|
import { pathToFileURL, fileURLToPath } from 'url';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import * as z42 from 'zod/v4';
|
|
@@ -8,11 +8,12 @@ import { ZodFirstPartyTypeKind } from 'zod/v3';
|
|
|
8
8
|
import { execFile, spawn } from 'child_process';
|
|
9
9
|
import fs4, { existsSync, readFileSync, constants, rmSync } from 'fs';
|
|
10
10
|
import * as fs from 'fs/promises';
|
|
11
|
-
import fs__default, { mkdir, writeFile, stat, readFile,
|
|
11
|
+
import fs__default, { mkdir, writeFile, stat, readFile, lstat, rename, rm, readdir, open as open$1, unlink, rmdir, realpath, mkdtemp, chmod } from 'fs/promises';
|
|
12
12
|
import { createRequire } from 'module';
|
|
13
13
|
import os, { homedir, tmpdir, userInfo } from 'os';
|
|
14
14
|
import { promisify } from 'util';
|
|
15
15
|
import crypto, { randomUUID, createHash } from 'crypto';
|
|
16
|
+
import { setTimeout as setTimeout$1 } from 'timers/promises';
|
|
16
17
|
import { Command } from 'commander';
|
|
17
18
|
import { render, useApp, useInput, Box, Text } from 'ink';
|
|
18
19
|
import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|
@@ -942,11 +943,11 @@ function isNodeDefaultFetch(fetch2) {
|
|
|
942
943
|
return source.includes("internal/deps/undici") || source.includes("lazy loading of undici");
|
|
943
944
|
}
|
|
944
945
|
async function createSafeNodeFetch() {
|
|
945
|
-
const [{ createRequire:
|
|
946
|
+
const [{ createRequire: createRequire4 }, { lookup }] = await Promise.all([
|
|
946
947
|
loadNodeModule("node:module"),
|
|
947
948
|
loadNodeModule("node:dns")
|
|
948
949
|
]);
|
|
949
|
-
const { Agent, fetch: fetch2 } =
|
|
950
|
+
const { Agent, fetch: fetch2 } = createRequire4(getCurrentModulePath())(
|
|
950
951
|
"undici"
|
|
951
952
|
);
|
|
952
953
|
const dispatcher = new Agent({
|
|
@@ -2454,7 +2455,7 @@ function createProviderToolFactory({
|
|
|
2454
2455
|
inputSchema
|
|
2455
2456
|
}) {
|
|
2456
2457
|
return ({
|
|
2457
|
-
execute,
|
|
2458
|
+
execute: execute2,
|
|
2458
2459
|
outputSchema,
|
|
2459
2460
|
needsApproval,
|
|
2460
2461
|
toModelOutput,
|
|
@@ -2468,7 +2469,7 @@ function createProviderToolFactory({
|
|
|
2468
2469
|
args,
|
|
2469
2470
|
inputSchema,
|
|
2470
2471
|
outputSchema,
|
|
2471
|
-
execute,
|
|
2472
|
+
execute: execute2,
|
|
2472
2473
|
needsApproval,
|
|
2473
2474
|
toModelOutput,
|
|
2474
2475
|
onInputStart,
|
|
@@ -2483,7 +2484,7 @@ function createProviderToolFactoryWithOutputSchema({
|
|
|
2483
2484
|
supportsDeferredResults
|
|
2484
2485
|
}) {
|
|
2485
2486
|
return ({
|
|
2486
|
-
execute,
|
|
2487
|
+
execute: execute2,
|
|
2487
2488
|
needsApproval,
|
|
2488
2489
|
toModelOutput,
|
|
2489
2490
|
onInputStart,
|
|
@@ -2496,7 +2497,7 @@ function createProviderToolFactoryWithOutputSchema({
|
|
|
2496
2497
|
args,
|
|
2497
2498
|
inputSchema,
|
|
2498
2499
|
outputSchema,
|
|
2499
|
-
execute,
|
|
2500
|
+
execute: execute2,
|
|
2500
2501
|
needsApproval,
|
|
2501
2502
|
toModelOutput,
|
|
2502
2503
|
onInputStart,
|
|
@@ -2654,11 +2655,11 @@ function isAsyncIterable(obj) {
|
|
|
2654
2655
|
return obj != null && typeof obj[Symbol.asyncIterator] === "function";
|
|
2655
2656
|
}
|
|
2656
2657
|
async function* executeTool({
|
|
2657
|
-
execute,
|
|
2658
|
+
execute: execute2,
|
|
2658
2659
|
input,
|
|
2659
2660
|
options
|
|
2660
2661
|
}) {
|
|
2661
|
-
const result =
|
|
2662
|
+
const result = execute2(input, options);
|
|
2662
2663
|
if (isAsyncIterable(result)) {
|
|
2663
2664
|
let lastOutput;
|
|
2664
2665
|
for await (const output of result) {
|
|
@@ -3563,6 +3564,30 @@ var init_pythonRuntime = __esm({
|
|
|
3563
3564
|
exec = promisify(execFile);
|
|
3564
3565
|
}
|
|
3565
3566
|
});
|
|
3567
|
+
|
|
3568
|
+
// src/evals/cowork/driver.ts
|
|
3569
|
+
var COMPUTER_USE_TOKEN_FIELDS, CoworkDriverError, CoworkHitlBudgetError;
|
|
3570
|
+
var init_driver = __esm({
|
|
3571
|
+
"src/evals/cowork/driver.ts"() {
|
|
3572
|
+
init_esm_shims();
|
|
3573
|
+
COMPUTER_USE_TOKEN_FIELDS = [
|
|
3574
|
+
"input_tokens",
|
|
3575
|
+
"output_tokens",
|
|
3576
|
+
"cache_creation_input_tokens",
|
|
3577
|
+
"cache_read_input_tokens"
|
|
3578
|
+
];
|
|
3579
|
+
CoworkDriverError = class extends Error {
|
|
3580
|
+
constructor(message, telemetry2) {
|
|
3581
|
+
super(message);
|
|
3582
|
+
this.telemetry = telemetry2;
|
|
3583
|
+
}
|
|
3584
|
+
kind = "failed";
|
|
3585
|
+
};
|
|
3586
|
+
CoworkHitlBudgetError = class extends CoworkDriverError {
|
|
3587
|
+
kind = "hitl-budget-exhausted";
|
|
3588
|
+
};
|
|
3589
|
+
}
|
|
3590
|
+
});
|
|
3566
3591
|
function resolveDriverPath(env) {
|
|
3567
3592
|
const configuredRoot = env.MST_COWORK_DRIVER_ROOT;
|
|
3568
3593
|
if (configuredRoot) {
|
|
@@ -3616,7 +3641,7 @@ async function runComputerUseDriver(query2, options, mode, label) {
|
|
|
3616
3641
|
const childError = error;
|
|
3617
3642
|
stdout = String(childError.stdout ?? "");
|
|
3618
3643
|
const reported = parseLastJsonLine(stdout);
|
|
3619
|
-
const
|
|
3644
|
+
const telemetry3 = parseTelemetry(reported?.telemetry, env, "partial");
|
|
3620
3645
|
const details = error.killed === true ? "driver terminated before completion; not retrying" : "driver exited unsuccessfully; not retrying";
|
|
3621
3646
|
if (mode === "hitl" && reported?.status === "failed" && typeof reported.error === "string" && /^Computer Use HITL check exceeded \d+ actions after attempting a visible prompt$/.test(
|
|
3622
3647
|
reported.error
|
|
@@ -3626,13 +3651,13 @@ async function runComputerUseDriver(query2, options, mode, label) {
|
|
|
3626
3651
|
);
|
|
3627
3652
|
throw new ComputerUseHitlBudgetError(
|
|
3628
3653
|
`HITL inspection reached its ${maxActions}-action budget.`,
|
|
3629
|
-
|
|
3654
|
+
telemetry3
|
|
3630
3655
|
);
|
|
3631
3656
|
}
|
|
3632
3657
|
diagnostic(`Computer Use ${label} failed: ${details}`);
|
|
3633
3658
|
throw new ComputerUseDriverError(
|
|
3634
3659
|
`Computer Use ${label} failed: ${details}`,
|
|
3635
|
-
|
|
3660
|
+
telemetry3
|
|
3636
3661
|
);
|
|
3637
3662
|
}
|
|
3638
3663
|
diagnostic(
|
|
@@ -3652,11 +3677,11 @@ async function runComputerUseDriver(query2, options, mode, label) {
|
|
|
3652
3677
|
parseTelemetry(record.telemetry, env, "partial")
|
|
3653
3678
|
);
|
|
3654
3679
|
}
|
|
3655
|
-
const
|
|
3680
|
+
const telemetry2 = parseTelemetry(record.telemetry, env, "complete");
|
|
3656
3681
|
const common = {
|
|
3657
3682
|
action_count: record.action_count,
|
|
3658
3683
|
model: record.model,
|
|
3659
|
-
...
|
|
3684
|
+
...telemetry2 ? { telemetry: telemetry2 } : {}
|
|
3660
3685
|
};
|
|
3661
3686
|
diagnostic(
|
|
3662
3687
|
`Computer Use ${label} completed (actions=${common.action_count})`
|
|
@@ -3666,7 +3691,7 @@ async function runComputerUseDriver(query2, options, mode, label) {
|
|
|
3666
3691
|
if (submission?.action !== "key" || submission.text !== "enter") {
|
|
3667
3692
|
throw new ComputerUseDriverError(
|
|
3668
3693
|
"Computer Use submission returned an invalid submission boundary.",
|
|
3669
|
-
|
|
3694
|
+
telemetry2 ? { ...telemetry2, accounting: "partial" } : void 0
|
|
3670
3695
|
);
|
|
3671
3696
|
}
|
|
3672
3697
|
return {
|
|
@@ -3726,7 +3751,7 @@ function parseTelemetry(value, env, accounting) {
|
|
|
3726
3751
|
if (!usage || !coverage) return void 0;
|
|
3727
3752
|
const safeUsage = {};
|
|
3728
3753
|
const safeCoverage = {};
|
|
3729
|
-
for (const field of
|
|
3754
|
+
for (const field of COMPUTER_USE_TOKEN_FIELDS) {
|
|
3730
3755
|
const count = coverage[field];
|
|
3731
3756
|
if (!isCount(count) || count > record.planner_response_count)
|
|
3732
3757
|
return void 0;
|
|
@@ -3756,26 +3781,22 @@ function parseTelemetry(value, env, accounting) {
|
|
|
3756
3781
|
cost: { status: "unavailable" }
|
|
3757
3782
|
};
|
|
3758
3783
|
}
|
|
3759
|
-
var execFileAsync,
|
|
3784
|
+
var execFileAsync, ComputerUseDriverError, ComputerUseHitlBudgetError;
|
|
3760
3785
|
var init_anthropicComputerUse = __esm({
|
|
3761
3786
|
"src/evals/cowork/anthropicComputerUse.ts"() {
|
|
3762
3787
|
init_esm_shims();
|
|
3763
3788
|
init_pythonRuntime();
|
|
3789
|
+
init_driver();
|
|
3764
3790
|
execFileAsync = promisify(execFile);
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
"cache_read_input_tokens"
|
|
3770
|
-
];
|
|
3771
|
-
ComputerUseDriverError = class extends Error {
|
|
3772
|
-
constructor(message, telemetry) {
|
|
3773
|
-
super(message);
|
|
3774
|
-
this.telemetry = telemetry;
|
|
3791
|
+
ComputerUseDriverError = class extends CoworkDriverError {
|
|
3792
|
+
constructor(message, telemetry2) {
|
|
3793
|
+
super(message, telemetry2);
|
|
3794
|
+
this.telemetry = telemetry2;
|
|
3775
3795
|
}
|
|
3776
3796
|
};
|
|
3777
3797
|
ComputerUseHitlBudgetError = class extends ComputerUseDriverError {
|
|
3778
3798
|
name = "ComputerUseHitlBudgetError";
|
|
3799
|
+
kind = "hitl-budget-exhausted";
|
|
3779
3800
|
};
|
|
3780
3801
|
}
|
|
3781
3802
|
});
|
|
@@ -4324,6 +4345,9 @@ var init_bundle = __esm({
|
|
|
4324
4345
|
MAX_CREDENTIAL_BYTES = 64 * 1024;
|
|
4325
4346
|
}
|
|
4326
4347
|
});
|
|
4348
|
+
function macCoworkProfileDirectory() {
|
|
4349
|
+
return join(homedir(), "Library/Application Support/Claude-3p/configLibrary");
|
|
4350
|
+
}
|
|
4327
4351
|
function fail() {
|
|
4328
4352
|
throw new Error(ERROR2);
|
|
4329
4353
|
}
|
|
@@ -4739,9 +4763,69 @@ async function preflightMacCoworkSettings(options) {
|
|
|
4739
4763
|
try {
|
|
4740
4764
|
await validateInstall(options);
|
|
4741
4765
|
} catch {
|
|
4742
|
-
throw new Error(
|
|
4766
|
+
throw new Error(
|
|
4767
|
+
`${ERROR2}
|
|
4768
|
+
Run 'mst cowork setup' first if the Claude 3P profile library is missing.`
|
|
4769
|
+
);
|
|
4770
|
+
}
|
|
4771
|
+
}
|
|
4772
|
+
async function initializeMacCoworkProfile(profileDirectory = macCoworkProfileDirectory()) {
|
|
4773
|
+
if (process.platform !== "darwin")
|
|
4774
|
+
throw new Error("Cowork profile setup requires macOS.");
|
|
4775
|
+
const directory = resolve(profileDirectory);
|
|
4776
|
+
const parent = dirname(directory);
|
|
4777
|
+
await mkdir(parent, { recursive: true, mode: 448 });
|
|
4778
|
+
try {
|
|
4779
|
+
await validateEmptyCoworkProfile(directory);
|
|
4780
|
+
return { profileDirectory: directory, created: false };
|
|
4781
|
+
} catch {
|
|
4782
|
+
try {
|
|
4783
|
+
await lstat(directory);
|
|
4784
|
+
} catch (error) {
|
|
4785
|
+
if (error.code !== "ENOENT") throw error;
|
|
4786
|
+
const temporary = `${directory}.mst-init-${randomUUID()}`;
|
|
4787
|
+
await mkdir(temporary, { mode: 448 });
|
|
4788
|
+
const id = randomUUID();
|
|
4789
|
+
try {
|
|
4790
|
+
await writeFile(
|
|
4791
|
+
join(temporary, "_meta.json"),
|
|
4792
|
+
JSON.stringify({
|
|
4793
|
+
appliedId: id,
|
|
4794
|
+
entries: [{ id, name: "MST base" }]
|
|
4795
|
+
}) + "\n",
|
|
4796
|
+
{ mode: 384 }
|
|
4797
|
+
);
|
|
4798
|
+
await writeFile(join(temporary, `${id}.json`), "{}\n", {
|
|
4799
|
+
mode: 384
|
|
4800
|
+
});
|
|
4801
|
+
await rename(temporary, directory);
|
|
4802
|
+
return { profileDirectory: directory, created: true };
|
|
4803
|
+
} catch (setupError) {
|
|
4804
|
+
await rm(temporary, { recursive: true, force: true }).catch(() => {
|
|
4805
|
+
});
|
|
4806
|
+
if (setupError.code === "EEXIST") {
|
|
4807
|
+
await validateEmptyCoworkProfile(directory);
|
|
4808
|
+
return { profileDirectory: directory, created: false };
|
|
4809
|
+
}
|
|
4810
|
+
throw setupError;
|
|
4811
|
+
}
|
|
4812
|
+
}
|
|
4813
|
+
throw new Error(
|
|
4814
|
+
"Claude 3P profile exists but is not an empty MST-managed profile. No files were changed."
|
|
4815
|
+
);
|
|
4743
4816
|
}
|
|
4744
4817
|
}
|
|
4818
|
+
async function validateEmptyCoworkProfile(directory) {
|
|
4819
|
+
const original = await readBytes(join(directory, "_meta.json"));
|
|
4820
|
+
const meta = metadata(original);
|
|
4821
|
+
const source = JSON.parse(
|
|
4822
|
+
(await readBytes(join(directory, `${meta.appliedId}.json`))).toString(
|
|
4823
|
+
"utf8"
|
|
4824
|
+
)
|
|
4825
|
+
);
|
|
4826
|
+
if (typeof source !== "object" || source === null || Array.isArray(source) || Object.keys(source).length !== 0)
|
|
4827
|
+
throw new Error("Claude 3P profile is not empty.");
|
|
4828
|
+
}
|
|
4745
4829
|
async function installMacCoworkSettings(options) {
|
|
4746
4830
|
let lock;
|
|
4747
4831
|
let journal;
|
|
@@ -4948,7 +5032,7 @@ async function prepareMacCoworkSession(options) {
|
|
|
4948
5032
|
const { running: wasRunning } = await controller.state();
|
|
4949
5033
|
await mkdir(lease, { mode: 448 });
|
|
4950
5034
|
const receiptPath = join(lease, "session.json");
|
|
4951
|
-
const
|
|
5035
|
+
const receipt2 = Buffer.from(
|
|
4952
5036
|
JSON.stringify({
|
|
4953
5037
|
version: 1,
|
|
4954
5038
|
nonce: randomUUID(),
|
|
@@ -4961,7 +5045,7 @@ async function prepareMacCoworkSession(options) {
|
|
|
4961
5045
|
let leaseInfo;
|
|
4962
5046
|
try {
|
|
4963
5047
|
leaseInfo = await lstat(lease);
|
|
4964
|
-
await writeFile(receiptPath,
|
|
5048
|
+
await writeFile(receiptPath, receipt2, { mode: 384, flag: "wx" });
|
|
4965
5049
|
} catch {
|
|
4966
5050
|
try {
|
|
4967
5051
|
await rmdir(lease);
|
|
@@ -4973,7 +5057,7 @@ async function prepareMacCoworkSession(options) {
|
|
|
4973
5057
|
let installAttempted = false;
|
|
4974
5058
|
const ownsLease = async () => {
|
|
4975
5059
|
const current = await lstat(lease);
|
|
4976
|
-
if (!current.isDirectory() || current.isSymbolicLink() || current.dev !== leaseInfo.dev || current.ino !== leaseInfo.ino || current.uid !== process.getuid?.() || (current.mode & 63) !== 0 || !(await privateBytes(receiptPath)).equals(
|
|
5060
|
+
if (!current.isDirectory() || current.isSymbolicLink() || current.dev !== leaseInfo.dev || current.ino !== leaseInfo.ino || current.uid !== process.getuid?.() || (current.mode & 63) !== 0 || !(await privateBytes(receiptPath)).equals(receipt2))
|
|
4977
5061
|
throw new Error(ERROR3);
|
|
4978
5062
|
const names = await readdir(lease);
|
|
4979
5063
|
if (names.length !== 1 || names[0] !== "session.json")
|
|
@@ -5025,7 +5109,7 @@ async function prepareMacCoworkSession(options) {
|
|
|
5025
5109
|
} catch {
|
|
5026
5110
|
const after = await lstat(lease);
|
|
5027
5111
|
if (after.isDirectory() && after.dev === leaseInfo.dev && after.ino === leaseInfo.ino)
|
|
5028
|
-
await writeFile(receiptPath,
|
|
5112
|
+
await writeFile(receiptPath, receipt2, { mode: 384, flag: "wx" });
|
|
5029
5113
|
throw new Error(ERROR3);
|
|
5030
5114
|
}
|
|
5031
5115
|
} catch {
|
|
@@ -5130,16 +5214,16 @@ async function recoverMacCoworkSession() {
|
|
|
5130
5214
|
if (!leaseInfo.isDirectory() || leaseInfo.isSymbolicLink() || leaseInfo.uid !== process.getuid?.() || leaseInfo.mode & 63)
|
|
5131
5215
|
throw new Error("Recovery lease is not a private owned directory.");
|
|
5132
5216
|
const bytes = await privateFile(receiptPath);
|
|
5133
|
-
const
|
|
5134
|
-
if (
|
|
5217
|
+
const receipt2 = Receipt.parse(JSON.parse(bytes.toString("utf8")));
|
|
5218
|
+
if (receipt2.profileDirectory !== profile)
|
|
5135
5219
|
throw new Error("Recovery profile mismatch.");
|
|
5136
|
-
assertStoppedOwner(
|
|
5220
|
+
assertStoppedOwner(receipt2.pid);
|
|
5137
5221
|
await mkdir(gate, { mode: 448 });
|
|
5138
5222
|
const verifyLease = async () => {
|
|
5139
5223
|
const current = await lstat(lease);
|
|
5140
5224
|
if (current.dev !== leaseInfo.dev || current.ino !== leaseInfo.ino || !(await privateFile(receiptPath)).equals(bytes) || (await readdir(lease)).join() !== "session.json")
|
|
5141
5225
|
throw new Error("Recovery lease changed; refusing cleanup.");
|
|
5142
|
-
assertStoppedOwner(
|
|
5226
|
+
assertStoppedOwner(receipt2.pid);
|
|
5143
5227
|
};
|
|
5144
5228
|
try {
|
|
5145
5229
|
await verifyLease();
|
|
@@ -5148,9 +5232,9 @@ async function recoverMacCoworkSession() {
|
|
|
5148
5232
|
const journal = JSON.parse(
|
|
5149
5233
|
(await privateFile(join(transaction, "journal.json"))).toString("utf8")
|
|
5150
5234
|
);
|
|
5151
|
-
if (journal.directory !==
|
|
5235
|
+
if (journal.directory !== receipt2.stagingDirectory)
|
|
5152
5236
|
throw new Error("Recovery staging mismatch.");
|
|
5153
|
-
} else if (await exists3(
|
|
5237
|
+
} else if (await exists3(receipt2.stagingDirectory))
|
|
5154
5238
|
throw new Error(
|
|
5155
5239
|
"Staging exists without its transaction; recovery refused."
|
|
5156
5240
|
);
|
|
@@ -5160,10 +5244,10 @@ async function recoverMacCoworkSession() {
|
|
|
5160
5244
|
throw new Error("Claude did not stop; recovery refused.");
|
|
5161
5245
|
await verifyLease();
|
|
5162
5246
|
if (hasTransaction) await restoreMacCoworkSettings(profile);
|
|
5163
|
-
if (await exists3(transaction) || await exists3(
|
|
5247
|
+
if (await exists3(transaction) || await exists3(receipt2.stagingDirectory))
|
|
5164
5248
|
throw new Error("Recovery state remains; lease retained.");
|
|
5165
|
-
if (
|
|
5166
|
-
if ((await controller.state()).running !==
|
|
5249
|
+
if (receipt2.wasRunning) await controller.start();
|
|
5250
|
+
if ((await controller.state()).running !== receipt2.wasRunning)
|
|
5167
5251
|
throw new Error(
|
|
5168
5252
|
"Could not restore prior Claude running state; lease retained."
|
|
5169
5253
|
);
|
|
@@ -5231,6 +5315,240 @@ var init_macos = __esm({
|
|
|
5231
5315
|
}
|
|
5232
5316
|
});
|
|
5233
5317
|
|
|
5318
|
+
// src/evals/cowork/linux.ts
|
|
5319
|
+
var linux_exports = {};
|
|
5320
|
+
__export(linux_exports, {
|
|
5321
|
+
linuxCoworkPlatform: () => linuxCoworkPlatform
|
|
5322
|
+
});
|
|
5323
|
+
async function readSettings(file) {
|
|
5324
|
+
const handle = await open$1(
|
|
5325
|
+
file,
|
|
5326
|
+
constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK
|
|
5327
|
+
);
|
|
5328
|
+
try {
|
|
5329
|
+
const metadata2 = await handle.stat();
|
|
5330
|
+
if (!metadata2.isFile() || metadata2.size > 1024 * 1024)
|
|
5331
|
+
throw new Error("Invalid prepared settings file.");
|
|
5332
|
+
return JSON.parse(await handle.readFile("utf8"));
|
|
5333
|
+
} finally {
|
|
5334
|
+
await handle.close();
|
|
5335
|
+
}
|
|
5336
|
+
}
|
|
5337
|
+
function telemetry(started, actions, accounting) {
|
|
5338
|
+
return {
|
|
5339
|
+
driver: "linux-desktop",
|
|
5340
|
+
accounting,
|
|
5341
|
+
duration_ms: Math.max(0, Date.now() - started),
|
|
5342
|
+
action_count: actions,
|
|
5343
|
+
planner: { status: "not-applicable" },
|
|
5344
|
+
cost: { status: "not-applicable" }
|
|
5345
|
+
};
|
|
5346
|
+
}
|
|
5347
|
+
function receipt(stdout) {
|
|
5348
|
+
try {
|
|
5349
|
+
const parsed = JSON.parse(stdout);
|
|
5350
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
5351
|
+
const r = parsed;
|
|
5352
|
+
if (!["ready", "submitted", "hitl_checked", "failed"].includes(
|
|
5353
|
+
String(r.status)
|
|
5354
|
+
) || typeof r.action_count !== "number" || !Number.isSafeInteger(r.action_count) || r.action_count < 0 || typeof r.duration_ms !== "number" || !Number.isFinite(r.duration_ms) || r.duration_ms < 0)
|
|
5355
|
+
return void 0;
|
|
5356
|
+
return {
|
|
5357
|
+
status: r.status,
|
|
5358
|
+
action_count: r.action_count,
|
|
5359
|
+
duration_ms: r.duration_ms,
|
|
5360
|
+
errorCode: typeof r.error === "string" && /^[a-z_]{1,64}$/.test(r.error) ? r.error : void 0
|
|
5361
|
+
};
|
|
5362
|
+
} catch {
|
|
5363
|
+
return void 0;
|
|
5364
|
+
}
|
|
5365
|
+
}
|
|
5366
|
+
async function execute(mode, payload, options) {
|
|
5367
|
+
const started = Date.now();
|
|
5368
|
+
const remaining = options.deadlineAt - started;
|
|
5369
|
+
if (remaining <= 0)
|
|
5370
|
+
throw new CoworkDriverError(
|
|
5371
|
+
"Linux desktop deadline exceeded; no action attempted."
|
|
5372
|
+
);
|
|
5373
|
+
const env = { ...process.env, ...options.env };
|
|
5374
|
+
if (!env.DISPLAY || !env.DBUS_SESSION_BUS_ADDRESS)
|
|
5375
|
+
throw new CoworkDriverError(
|
|
5376
|
+
"Linux Cowork requires a prepared DISPLAY and D-Bus desktop session."
|
|
5377
|
+
);
|
|
5378
|
+
if (env.MST_COWORK_URL_OPENER !== void 0 && !isAbsolute(env.MST_COWORK_URL_OPENER))
|
|
5379
|
+
throw new CoworkDriverError(
|
|
5380
|
+
"MST_COWORK_URL_OPENER must be an absolute executable path."
|
|
5381
|
+
);
|
|
5382
|
+
const script = createRequire(
|
|
5383
|
+
typeof __filename$1 === "string" ? __filename$1 : import.meta.url
|
|
5384
|
+
).resolve("@gleanwork/mcp-server-tester/cowork-linux-runtime");
|
|
5385
|
+
const timeout = Math.min(remaining, mode === "submit" ? 6e4 : 1e4);
|
|
5386
|
+
const driverTimeout = Math.max(
|
|
5387
|
+
1,
|
|
5388
|
+
Math.floor(timeout - Math.min(1e3, timeout / 10))
|
|
5389
|
+
);
|
|
5390
|
+
const result = await new Promise(
|
|
5391
|
+
(resolve10) => {
|
|
5392
|
+
const child = execFile(
|
|
5393
|
+
env.MST_COWORK_PYTHON ?? "python3",
|
|
5394
|
+
[
|
|
5395
|
+
script,
|
|
5396
|
+
"--mode",
|
|
5397
|
+
mode,
|
|
5398
|
+
"--timeout-ms",
|
|
5399
|
+
String(driverTimeout),
|
|
5400
|
+
"--max-actions",
|
|
5401
|
+
String(options.maxActions ?? 24)
|
|
5402
|
+
],
|
|
5403
|
+
{
|
|
5404
|
+
timeout,
|
|
5405
|
+
killSignal: "SIGKILL",
|
|
5406
|
+
maxBuffer: 64 * 1024,
|
|
5407
|
+
env: {
|
|
5408
|
+
...Object.fromEntries(
|
|
5409
|
+
SESSION_ENV.flatMap((k) => env[k] ? [[k, env[k]]] : [])
|
|
5410
|
+
),
|
|
5411
|
+
NO_AT_BRIDGE: "0"
|
|
5412
|
+
}
|
|
5413
|
+
},
|
|
5414
|
+
(error, stdout) => resolve10({ failed: error !== null, stdout: String(stdout) })
|
|
5415
|
+
);
|
|
5416
|
+
child.stdin?.on("error", () => {
|
|
5417
|
+
});
|
|
5418
|
+
child.stdin?.end(JSON.stringify(payload));
|
|
5419
|
+
}
|
|
5420
|
+
);
|
|
5421
|
+
const record = receipt(result.stdout);
|
|
5422
|
+
const expected = mode === "probe" ? "ready" : mode === "submit" ? "submitted" : "hitl_checked";
|
|
5423
|
+
if (result.failed || record?.status !== expected || record.action_count > (options.maxActions ?? 24))
|
|
5424
|
+
throw new CoworkDriverError(
|
|
5425
|
+
`Linux desktop ${mode} failed or its receipt was uncertain (${record?.errorCode ?? "missing_or_invalid_receipt"}); no retry attempted.`,
|
|
5426
|
+
record ? telemetry(started, record.action_count, "partial") : void 0
|
|
5427
|
+
);
|
|
5428
|
+
return record;
|
|
5429
|
+
}
|
|
5430
|
+
var SESSION_ENV, linuxCoworkPlatform;
|
|
5431
|
+
var init_linux = __esm({
|
|
5432
|
+
"src/evals/cowork/linux.ts"() {
|
|
5433
|
+
init_esm_shims();
|
|
5434
|
+
init_driver();
|
|
5435
|
+
SESSION_ENV = [
|
|
5436
|
+
"PATH",
|
|
5437
|
+
"HOME",
|
|
5438
|
+
"DISPLAY",
|
|
5439
|
+
"XAUTHORITY",
|
|
5440
|
+
"DBUS_SESSION_BUS_ADDRESS",
|
|
5441
|
+
"AT_SPI_BUS_ADDRESS",
|
|
5442
|
+
"XDG_RUNTIME_DIR",
|
|
5443
|
+
"XDG_CONFIG_HOME",
|
|
5444
|
+
"MST_COWORK_URL_OPENER",
|
|
5445
|
+
"LANG",
|
|
5446
|
+
"LC_ALL"
|
|
5447
|
+
];
|
|
5448
|
+
linuxCoworkPlatform = {
|
|
5449
|
+
dataDirectory: (options) => options.dataDir ?? join(
|
|
5450
|
+
process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"),
|
|
5451
|
+
"Claude-3p",
|
|
5452
|
+
"local-agent-mode-sessions"
|
|
5453
|
+
),
|
|
5454
|
+
async prepare({ manifest, env, model }) {
|
|
5455
|
+
const settingsFile = env.MST_COWORK_SETTINGS_FILE ?? "/etc/claude-desktop/managed-settings.json";
|
|
5456
|
+
if (!isAbsolute(settingsFile))
|
|
5457
|
+
throw new Error("Linux Cowork settings path must be absolute.");
|
|
5458
|
+
try {
|
|
5459
|
+
const settings = await readSettings(settingsFile);
|
|
5460
|
+
const models = settings.inferenceModels;
|
|
5461
|
+
if (model && !models?.some((m) => m.name === model))
|
|
5462
|
+
throw new Error("model");
|
|
5463
|
+
const expected = manifest.servers ?? [];
|
|
5464
|
+
const actual = settings.managedMcpServers;
|
|
5465
|
+
if (!Array.isArray(actual) || actual.length !== expected.length || settings.allowManagedMcpServersOnly !== true)
|
|
5466
|
+
throw new Error("servers");
|
|
5467
|
+
for (const [index, server] of expected.entries()) {
|
|
5468
|
+
if (server.transport !== "http") throw new Error("transport");
|
|
5469
|
+
const observed = actual.find(
|
|
5470
|
+
(s) => s.name === (server.label ?? `server-${index + 1}`)
|
|
5471
|
+
);
|
|
5472
|
+
if (!observed || observed.transport !== "http" || observed.url !== server.serverUrl)
|
|
5473
|
+
throw new Error("server");
|
|
5474
|
+
if (observed.toolPolicy?.["*"] === "allow" && manifest.coworkSetup?.approveWriteTools !== true)
|
|
5475
|
+
throw new Error("policy");
|
|
5476
|
+
}
|
|
5477
|
+
} catch {
|
|
5478
|
+
throw new Error(
|
|
5479
|
+
"Prepared Linux desktop settings do not match the eval model, MCP servers, or approval policy."
|
|
5480
|
+
);
|
|
5481
|
+
}
|
|
5482
|
+
await execute(
|
|
5483
|
+
"probe",
|
|
5484
|
+
{},
|
|
5485
|
+
{ deadlineAt: Date.now() + 15e3, maxActions: 1, env }
|
|
5486
|
+
);
|
|
5487
|
+
return {
|
|
5488
|
+
async dispose() {
|
|
5489
|
+
}
|
|
5490
|
+
};
|
|
5491
|
+
},
|
|
5492
|
+
async recover() {
|
|
5493
|
+
throw new Error(
|
|
5494
|
+
"Linux desktop recovery belongs to the runtime owner, not the MST driver."
|
|
5495
|
+
);
|
|
5496
|
+
},
|
|
5497
|
+
async submit(query2, options) {
|
|
5498
|
+
const started = Date.now();
|
|
5499
|
+
const result = await execute("submit", { prompt: query2 }, options);
|
|
5500
|
+
return {
|
|
5501
|
+
status: "submitted",
|
|
5502
|
+
action_count: result.action_count,
|
|
5503
|
+
telemetry: telemetry(started, result.action_count, "complete")
|
|
5504
|
+
};
|
|
5505
|
+
},
|
|
5506
|
+
async handleHitl(options) {
|
|
5507
|
+
if (!options.isComplete)
|
|
5508
|
+
throw new Error("Linux HITL requires a bound native completion check.");
|
|
5509
|
+
const started = Date.now();
|
|
5510
|
+
let actions = 0;
|
|
5511
|
+
const budget = options.maxActions ?? 12;
|
|
5512
|
+
try {
|
|
5513
|
+
while (Date.now() < options.deadlineAt) {
|
|
5514
|
+
if (await options.isComplete())
|
|
5515
|
+
return {
|
|
5516
|
+
status: "hitl_checked",
|
|
5517
|
+
action_count: actions,
|
|
5518
|
+
telemetry: telemetry(started, actions, "complete")
|
|
5519
|
+
};
|
|
5520
|
+
if (actions >= budget)
|
|
5521
|
+
throw new CoworkHitlBudgetError(
|
|
5522
|
+
"Linux HITL action budget exhausted.",
|
|
5523
|
+
telemetry(started, actions, "partial")
|
|
5524
|
+
);
|
|
5525
|
+
const result = await execute(
|
|
5526
|
+
"hitl",
|
|
5527
|
+
{ approveWriteTools: options.approveWriteTools === true },
|
|
5528
|
+
{ ...options, maxActions: budget - actions }
|
|
5529
|
+
);
|
|
5530
|
+
actions += result.action_count;
|
|
5531
|
+
await setTimeout$1(
|
|
5532
|
+
Math.min(500, Math.max(0, options.deadlineAt - Date.now()))
|
|
5533
|
+
);
|
|
5534
|
+
}
|
|
5535
|
+
} catch (error) {
|
|
5536
|
+
if (error instanceof CoworkHitlBudgetError) throw error;
|
|
5537
|
+
const partialActions = error instanceof CoworkDriverError ? error.telemetry?.action_count ?? 0 : 0;
|
|
5538
|
+
throw new CoworkDriverError(
|
|
5539
|
+
"Linux HITL failed for the bound native session.",
|
|
5540
|
+
telemetry(started, actions + partialActions, "partial")
|
|
5541
|
+
);
|
|
5542
|
+
}
|
|
5543
|
+
throw new CoworkDriverError(
|
|
5544
|
+
"Linux HITL deadline exceeded.",
|
|
5545
|
+
telemetry(started, actions, "partial")
|
|
5546
|
+
);
|
|
5547
|
+
}
|
|
5548
|
+
};
|
|
5549
|
+
}
|
|
5550
|
+
});
|
|
5551
|
+
|
|
5234
5552
|
// src/cli/index.ts
|
|
5235
5553
|
init_esm_shims();
|
|
5236
5554
|
|
|
@@ -5312,7 +5630,7 @@ init_esm_shims();
|
|
|
5312
5630
|
|
|
5313
5631
|
// package.json
|
|
5314
5632
|
var package_default = {
|
|
5315
|
-
version: "2.0.0-beta.
|
|
5633
|
+
version: "2.0.0-beta.3"};
|
|
5316
5634
|
|
|
5317
5635
|
// src/cli/templates/index.ts
|
|
5318
5636
|
function getPlaywrightConfigTemplate(answers) {
|
|
@@ -7053,8 +7371,8 @@ ${errorText}`
|
|
|
7053
7371
|
return;
|
|
7054
7372
|
}
|
|
7055
7373
|
try {
|
|
7056
|
-
const
|
|
7057
|
-
await
|
|
7374
|
+
const open6 = await import('open');
|
|
7375
|
+
await open6.default(url.toString());
|
|
7058
7376
|
debug2("Opened browser for authentication");
|
|
7059
7377
|
} catch (error) {
|
|
7060
7378
|
debug2("Failed to open browser:", error);
|
|
@@ -10502,11 +10820,13 @@ init_esm_shims();
|
|
|
10502
10820
|
|
|
10503
10821
|
// src/evals/cowork/platform.ts
|
|
10504
10822
|
init_esm_shims();
|
|
10505
|
-
async function getCoworkPlatform() {
|
|
10506
|
-
if (process.platform === "darwin")
|
|
10823
|
+
async function getCoworkPlatform(provider) {
|
|
10824
|
+
if (process.platform === "darwin" && provider === "anthropic-computer-use")
|
|
10507
10825
|
return (await Promise.resolve().then(() => (init_macos(), macos_exports))).macCoworkPlatform;
|
|
10826
|
+
if (process.platform === "linux" && provider === "linux-desktop")
|
|
10827
|
+
return (await Promise.resolve().then(() => (init_linux(), linux_exports))).linuxCoworkPlatform;
|
|
10508
10828
|
throw new Error(
|
|
10509
|
-
`Cowork
|
|
10829
|
+
`Cowork driver ${provider} is not supported on ${process.platform}.`
|
|
10510
10830
|
);
|
|
10511
10831
|
}
|
|
10512
10832
|
|
|
@@ -11092,7 +11412,7 @@ async function waitForClaudeMatch(options, requireCompletion) {
|
|
|
11092
11412
|
}
|
|
11093
11413
|
lastPending = trace;
|
|
11094
11414
|
}
|
|
11095
|
-
await
|
|
11415
|
+
await delay3(POLL_INTERVAL_MS);
|
|
11096
11416
|
}
|
|
11097
11417
|
if (lastPending) {
|
|
11098
11418
|
throw new Error(
|
|
@@ -11255,7 +11575,7 @@ async function waitForAccessibilityTrace(options) {
|
|
|
11255
11575
|
if (fallback) {
|
|
11256
11576
|
return fallback;
|
|
11257
11577
|
}
|
|
11258
|
-
await
|
|
11578
|
+
await delay3(POLL_INTERVAL_MS);
|
|
11259
11579
|
}
|
|
11260
11580
|
throw new Error(
|
|
11261
11581
|
`Timed out waiting for Claude Chat Desktop visible response for marker ${options.context.marker}`
|
|
@@ -11344,6 +11664,7 @@ async function parseClaudeTrace(candidate, marker16) {
|
|
|
11344
11664
|
auditParsed,
|
|
11345
11665
|
transcriptParsed,
|
|
11346
11666
|
usageAvailable: usage !== void 0,
|
|
11667
|
+
knownUsageFields: knownUsageFields(resultEvents),
|
|
11347
11668
|
costAvailable: resultEvents.some(
|
|
11348
11669
|
(event) => typeof event.total_cost_usd === "number"
|
|
11349
11670
|
),
|
|
@@ -11855,6 +12176,35 @@ function extractAggregatedUsage(events) {
|
|
|
11855
12176
|
cacheCreationInputTokens: (total.cacheCreationInputTokens ?? 0) + (value.cacheCreationInputTokens ?? 0)
|
|
11856
12177
|
}));
|
|
11857
12178
|
}
|
|
12179
|
+
function knownUsageFields(events) {
|
|
12180
|
+
const fields = [
|
|
12181
|
+
[
|
|
12182
|
+
"inputTokens",
|
|
12183
|
+
(event) => event.usage?.input_tokens ?? event.usage?.inputTokens
|
|
12184
|
+
],
|
|
12185
|
+
[
|
|
12186
|
+
"outputTokens",
|
|
12187
|
+
(event) => event.usage?.output_tokens ?? event.usage?.outputTokens
|
|
12188
|
+
],
|
|
12189
|
+
[
|
|
12190
|
+
"cacheReadInputTokens",
|
|
12191
|
+
(event) => event.usage?.cache_read_input_tokens ?? event.usage?.cacheReadInputTokens
|
|
12192
|
+
],
|
|
12193
|
+
[
|
|
12194
|
+
"cacheCreationInputTokens",
|
|
12195
|
+
(event) => event.usage?.cache_creation_input_tokens ?? event.usage?.cacheCreationInputTokens
|
|
12196
|
+
],
|
|
12197
|
+
["totalCostUsd", (event) => event.total_cost_usd],
|
|
12198
|
+
["durationMs", (event) => event.duration_ms],
|
|
12199
|
+
["durationApiMs", (event) => event.duration_api_ms]
|
|
12200
|
+
];
|
|
12201
|
+
return fields.filter(
|
|
12202
|
+
([key, value]) => events.length > 0 && events.every((event) => {
|
|
12203
|
+
const number = value(event);
|
|
12204
|
+
return typeof number === "number" && Number.isFinite(number) && number >= 0 && (key === "totalCostUsd" || Number.isSafeInteger(number));
|
|
12205
|
+
})
|
|
12206
|
+
).map(([key]) => key);
|
|
12207
|
+
}
|
|
11858
12208
|
function extractUsage(event) {
|
|
11859
12209
|
const usage = event.usage;
|
|
11860
12210
|
const inputTokens = getNumber(usage, "input_tokens") ?? getNumber(usage, "inputTokens");
|
|
@@ -11951,19 +12301,28 @@ function classifyTraceFailure(message) {
|
|
|
11951
12301
|
function formatError2(err) {
|
|
11952
12302
|
return err instanceof Error ? err.message : String(err);
|
|
11953
12303
|
}
|
|
11954
|
-
function
|
|
12304
|
+
function delay3(ms) {
|
|
11955
12305
|
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
11956
12306
|
}
|
|
11957
12307
|
|
|
11958
12308
|
// src/evals/coworkHost.ts
|
|
11959
|
-
|
|
12309
|
+
init_driver();
|
|
11960
12310
|
var OptionsSchema = z.object({
|
|
11961
|
-
computerUseProvider: z.
|
|
12311
|
+
computerUseProvider: z.enum(["anthropic-computer-use", "linux-desktop"]).default(
|
|
12312
|
+
() => process.platform === "linux" ? "linux-desktop" : "anthropic-computer-use"
|
|
12313
|
+
),
|
|
11962
12314
|
computerUseMaxActions: z.number().int().min(1).max(64).default(24),
|
|
11963
12315
|
hitlMaxActions: z.number().int().min(1).max(24).default(12),
|
|
11964
12316
|
computerUseModel: z.string().regex(/^[A-Za-z0-9._:-]+$/).optional(),
|
|
11965
12317
|
dataDir: z.string().min(1).optional()
|
|
11966
|
-
}).strict()
|
|
12318
|
+
}).strict().superRefine((options, context) => {
|
|
12319
|
+
if (options.computerUseProvider === "linux-desktop" && options.computerUseModel !== void 0)
|
|
12320
|
+
context.addIssue({
|
|
12321
|
+
code: "custom",
|
|
12322
|
+
path: ["computerUseModel"],
|
|
12323
|
+
message: "linux-desktop does not use a planner model."
|
|
12324
|
+
});
|
|
12325
|
+
});
|
|
11967
12326
|
var CoworkSchema = z.object({
|
|
11968
12327
|
type: z.string(),
|
|
11969
12328
|
options: OptionsSchema.default(() => OptionsSchema.parse({})),
|
|
@@ -11989,9 +12348,9 @@ async function runBatch(requests, context, selectedPlatform) {
|
|
|
11989
12348
|
);
|
|
11990
12349
|
const config = configs[0];
|
|
11991
12350
|
const env = { ...process.env, ...context.env, ...config.env };
|
|
11992
|
-
if (!env.ANTHROPIC_API_KEY)
|
|
12351
|
+
if (config.options.computerUseProvider === "anthropic-computer-use" && !env.ANTHROPIC_API_KEY)
|
|
11993
12352
|
throw new Error("ANTHROPIC_API_KEY is required for Cowork Computer Use.");
|
|
11994
|
-
const platform = await getCoworkPlatform();
|
|
12353
|
+
const platform = await getCoworkPlatform(config.options.computerUseProvider);
|
|
11995
12354
|
const dataDir = platform.dataDirectory(config.options);
|
|
11996
12355
|
const servers = requests[0].input.servers;
|
|
11997
12356
|
const { arms: _arms, ...manifest } = context.manifest;
|
|
@@ -12022,7 +12381,7 @@ async function runBatch(requests, context, selectedPlatform) {
|
|
|
12022
12381
|
active = true;
|
|
12023
12382
|
try {
|
|
12024
12383
|
if (env.MST_COWORK_RECOVER === "1") await platform.recover();
|
|
12025
|
-
if (servers.length || config.model)
|
|
12384
|
+
if (config.options.computerUseProvider === "linux-desktop" || servers.length || config.model)
|
|
12026
12385
|
session = await platform.prepare({
|
|
12027
12386
|
manifest: managedManifest,
|
|
12028
12387
|
env,
|
|
@@ -12082,7 +12441,7 @@ async function runBatch(requests, context, selectedPlatform) {
|
|
|
12082
12441
|
if (computerUse.submission.status !== "completed") {
|
|
12083
12442
|
computerUse.submission = {
|
|
12084
12443
|
status: "failed",
|
|
12085
|
-
...error instanceof
|
|
12444
|
+
...error instanceof CoworkDriverError && error.telemetry ? { telemetry: error.telemetry } : {}
|
|
12086
12445
|
};
|
|
12087
12446
|
}
|
|
12088
12447
|
results[index] = failure(safeError(error));
|
|
@@ -12121,6 +12480,18 @@ async function runBatch(requests, context, selectedPlatform) {
|
|
|
12121
12480
|
maxActions: config.options.hitlMaxActions,
|
|
12122
12481
|
model: config.options.computerUseModel,
|
|
12123
12482
|
env,
|
|
12483
|
+
approveWriteTools: context.manifest.coworkSetup?.approveWriteTools === true,
|
|
12484
|
+
isComplete: async () => {
|
|
12485
|
+
const current = await findMatchingClaudeSessions({
|
|
12486
|
+
...match,
|
|
12487
|
+
sessionPath
|
|
12488
|
+
});
|
|
12489
|
+
if (current.length !== 1)
|
|
12490
|
+
throw new Error(
|
|
12491
|
+
"Bound native session is missing or ambiguous."
|
|
12492
|
+
);
|
|
12493
|
+
return current[0].isComplete;
|
|
12494
|
+
},
|
|
12124
12495
|
task: `Handle only the currently open Cowork task just submitted with this exact query: ${request.input.scenario}. Do not switch tasks. Never create, type, or resubmit a task. If the current task cannot be identified uniquely, stop without an action.`
|
|
12125
12496
|
});
|
|
12126
12497
|
computerUse.hitl = {
|
|
@@ -12130,11 +12501,11 @@ async function runBatch(requests, context, selectedPlatform) {
|
|
|
12130
12501
|
}
|
|
12131
12502
|
} catch (error) {
|
|
12132
12503
|
computerUse.hitl = {
|
|
12133
|
-
status: error instanceof
|
|
12134
|
-
...error instanceof
|
|
12504
|
+
status: error instanceof CoworkDriverError && error.kind === "hitl-budget-exhausted" ? "budget-exhausted" : "failed",
|
|
12505
|
+
...error instanceof CoworkDriverError && error.telemetry ? { telemetry: error.telemetry } : {}
|
|
12135
12506
|
};
|
|
12136
12507
|
const message = safeError(error);
|
|
12137
|
-
if (error instanceof
|
|
12508
|
+
if (error instanceof CoworkDriverError && error.kind === "hitl-budget-exhausted") {
|
|
12138
12509
|
hitlWarning = message;
|
|
12139
12510
|
} else {
|
|
12140
12511
|
hitlError = message;
|
|
@@ -12287,7 +12658,7 @@ async function runBuiltinHost(input, host, context, factory) {
|
|
|
12287
12658
|
}
|
|
12288
12659
|
controller.signal.throwIfAborted();
|
|
12289
12660
|
}
|
|
12290
|
-
async function
|
|
12661
|
+
async function execute2() {
|
|
12291
12662
|
try {
|
|
12292
12663
|
checkDeadline();
|
|
12293
12664
|
if (config.hostType !== "cli") {
|
|
@@ -12365,9 +12736,9 @@ async function runBuiltinHost(input, host, context, factory) {
|
|
|
12365
12736
|
if (config.hostType === "cli" && config.cli?.claudeMcpServers !== void 0) {
|
|
12366
12737
|
void expired.catch(() => {
|
|
12367
12738
|
});
|
|
12368
|
-
return await
|
|
12739
|
+
return await execute2();
|
|
12369
12740
|
}
|
|
12370
|
-
const result = await Promise.race([
|
|
12741
|
+
const result = await Promise.race([execute2(), expired]);
|
|
12371
12742
|
checkDeadline();
|
|
12372
12743
|
return result;
|
|
12373
12744
|
} catch (error) {
|
|
@@ -16262,7 +16633,7 @@ async function runEvalSuite(options) {
|
|
|
16262
16633
|
for (const arm of armResults) {
|
|
16263
16634
|
totalHostUsage = sumUsage(totalHostUsage, arm.result?.totalHostUsage);
|
|
16264
16635
|
}
|
|
16265
|
-
const
|
|
16636
|
+
const telemetry2 = {
|
|
16266
16637
|
cases: allResults.length,
|
|
16267
16638
|
toolCalls: countToolCalls(allResults),
|
|
16268
16639
|
failedCases: allResults.filter((result) => !result.pass).length,
|
|
@@ -16282,7 +16653,7 @@ async function runEvalSuite(options) {
|
|
|
16282
16653
|
passRate: allResults.length > 0 ? allResults.filter((result) => result.pass).length / allResults.length : 0,
|
|
16283
16654
|
...computedMetrics
|
|
16284
16655
|
},
|
|
16285
|
-
telemetry,
|
|
16656
|
+
telemetry: telemetry2,
|
|
16286
16657
|
armDeltas: buildArmDeltas(armResults),
|
|
16287
16658
|
results: allResults
|
|
16288
16659
|
};
|
|
@@ -16594,6 +16965,26 @@ Batch complete: ${result.passed} passed, ${result.failed} failed, ${result.skipp
|
|
|
16594
16965
|
if (result.failed > 0) process.exitCode = 1;
|
|
16595
16966
|
}
|
|
16596
16967
|
|
|
16968
|
+
// src/cli/commands/cowork/index.ts
|
|
16969
|
+
init_esm_shims();
|
|
16970
|
+
init_macTransaction();
|
|
16971
|
+
async function setupCowork() {
|
|
16972
|
+
const result = await initializeMacCoworkProfile();
|
|
16973
|
+
if (result.created) {
|
|
16974
|
+
console.log(
|
|
16975
|
+
`Initialized the empty Claude 3P profile at ${result.profileDirectory}.`
|
|
16976
|
+
);
|
|
16977
|
+
console.log(
|
|
16978
|
+
"Next: launch Claude Desktop, sign in, open one normal conversation, quit Claude Desktop, then run the Cowork evaluation."
|
|
16979
|
+
);
|
|
16980
|
+
} else {
|
|
16981
|
+
console.log(`Claude 3P profile is ready at ${result.profileDirectory}.`);
|
|
16982
|
+
console.log(
|
|
16983
|
+
"If Claude Desktop is not signed in, launch it and complete sign-in before running the Cowork evaluation."
|
|
16984
|
+
);
|
|
16985
|
+
}
|
|
16986
|
+
}
|
|
16987
|
+
|
|
16597
16988
|
// src/cli/index.ts
|
|
16598
16989
|
var program = new Command();
|
|
16599
16990
|
program.name("mcp-server-tester").description("CLI tools for MCP server evaluation and testing").version(package_default.version);
|
|
@@ -16633,6 +17024,7 @@ program.command("batch").description("Run multiple evaluation manifests").option
|
|
|
16633
17024
|
dryRun: options.dryRun
|
|
16634
17025
|
})
|
|
16635
17026
|
);
|
|
17027
|
+
program.command("cowork").description("Prepare the local macOS Claude 3P profile for Cowork").command("setup").description("Initialize or validate the empty Claude 3P profile").action(setupCowork);
|
|
16636
17028
|
program.command("open").description("Open the MCP eval reporter UI in your browser").option(
|
|
16637
17029
|
"-d, --dir <directory>",
|
|
16638
17030
|
"Report output directory",
|