@workbench-ai/workbench 0.0.77 → 0.0.79
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/index.d.ts.map +1 -1
- package/dist/index.js +148 -23
- package/package.json +6 -6
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiEA,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC/B;AAuTD,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAE,KAGzD,GAAG,OAAO,CAAC,MAAM,CAAC,CAoMlB"}
|
package/dist/index.js
CHANGED
|
@@ -404,7 +404,7 @@ export async function runCli(argv, io = {
|
|
|
404
404
|
if (command === "diff") {
|
|
405
405
|
const range = optionalPositional(parsed, 1) ?? await defaultDiffRange(core);
|
|
406
406
|
const diffs = await diffWorkbenchVersions(range, core);
|
|
407
|
-
return output(diffs, parsed, io, () => diffs
|
|
407
|
+
return output(diffs, parsed, io, () => formatDiff(diffs));
|
|
408
408
|
}
|
|
409
409
|
if (command === "show") {
|
|
410
410
|
return await handleShow(parsed, io);
|
|
@@ -723,6 +723,7 @@ const API_REQUEST_MAX_ATTEMPTS = 3;
|
|
|
723
723
|
const API_REQUEST_GZIP_THRESHOLD_BYTES = 1024 * 1024;
|
|
724
724
|
const CLOUD_RUN_TIMEOUT_MS = 30 * 60 * 1000;
|
|
725
725
|
const CLOUD_RUN_POLL_INTERVAL_MS = 3000;
|
|
726
|
+
const LOGIN_WAIT_TIMEOUT_SECONDS = 120;
|
|
726
727
|
async function handleLogin(parsed, io) {
|
|
727
728
|
const provider = optionalPositional(parsed, 1);
|
|
728
729
|
if (provider) {
|
|
@@ -739,7 +740,7 @@ async function handleLogin(parsed, io) {
|
|
|
739
740
|
}
|
|
740
741
|
if (parsed.flags["start-only"] === true && parsed.flags.wait === true) {
|
|
741
742
|
throw new WorkbenchCodedError("usage", "workbench login accepts only one of --start-only or --wait.", {
|
|
742
|
-
remediation:
|
|
743
|
+
remediation: `Run workbench login --start-only or workbench login --wait --timeout ${LOGIN_WAIT_TIMEOUT_SECONDS}.`,
|
|
743
744
|
exitCode: 2,
|
|
744
745
|
});
|
|
745
746
|
}
|
|
@@ -748,7 +749,13 @@ async function handleLogin(parsed, io) {
|
|
|
748
749
|
const timeoutSeconds = intFlag(parsed, "timeout");
|
|
749
750
|
if (startOnly && timeoutSeconds !== undefined) {
|
|
750
751
|
throw new WorkbenchCodedError("usage", "workbench login --timeout only applies with --wait.", {
|
|
751
|
-
remediation:
|
|
752
|
+
remediation: `Run workbench login --start-only, then workbench login --wait --timeout ${LOGIN_WAIT_TIMEOUT_SECONDS}.`,
|
|
753
|
+
exitCode: 2,
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
if (waitOnly && timeoutSeconds === undefined) {
|
|
757
|
+
throw new WorkbenchCodedError("usage", "workbench login --wait requires --timeout N.", {
|
|
758
|
+
remediation: `Run workbench login --wait --timeout ${LOGIN_WAIT_TIMEOUT_SECONDS}.`,
|
|
752
759
|
exitCode: 2,
|
|
753
760
|
});
|
|
754
761
|
}
|
|
@@ -773,8 +780,8 @@ async function handleLogin(parsed, io) {
|
|
|
773
780
|
verificationUriComplete: record.verification_uri_complete,
|
|
774
781
|
userCode: record.user_code,
|
|
775
782
|
expiresAt: record.expiresAt,
|
|
776
|
-
resume:
|
|
777
|
-
}, parsed, io, () => `Open ${record.verification_uri_complete}\nCode: ${record.user_code}\nResume: workbench login --wait`);
|
|
783
|
+
resume: `workbench login --wait --timeout ${LOGIN_WAIT_TIMEOUT_SECONDS}`,
|
|
784
|
+
}, parsed, io, () => `Open ${record.verification_uri_complete}\nCode: ${record.user_code}\nResume: workbench login --wait --timeout ${LOGIN_WAIT_TIMEOUT_SECONDS}`);
|
|
778
785
|
}
|
|
779
786
|
await writePendingDeviceAuthorization(record);
|
|
780
787
|
if (freshAuthorization && !parsed.flags.json) {
|
|
@@ -1047,8 +1054,7 @@ function formatFanOut(fanout) {
|
|
|
1047
1054
|
if (fanout.linkedAgents.length === 0) {
|
|
1048
1055
|
return "fanout: completed";
|
|
1049
1056
|
}
|
|
1050
|
-
|
|
1051
|
-
return `fanout: linked ${count} ${count === 1 ? "agent" : "agents"}`;
|
|
1057
|
+
return "fanout: completed";
|
|
1052
1058
|
}
|
|
1053
1059
|
async function latestInstallVersion(record) {
|
|
1054
1060
|
const handle = normalizedOwnerSkillHandle(record.handle);
|
|
@@ -1727,7 +1733,7 @@ async function pollDeviceToken(baseUrl, authorization, timeoutSeconds) {
|
|
|
1727
1733
|
}
|
|
1728
1734
|
throw new WorkbenchCodedError("login_pending", "Device login is still waiting for browser authorization.", {
|
|
1729
1735
|
retryable: true,
|
|
1730
|
-
remediation:
|
|
1736
|
+
remediation: `Authorize the device in the browser, then run workbench login --wait --timeout ${LOGIN_WAIT_TIMEOUT_SECONDS}.`,
|
|
1731
1737
|
subject: {
|
|
1732
1738
|
retryAfterSeconds: Math.max(1, Math.ceil(intervalMs / 1000)),
|
|
1733
1739
|
verificationUri: authorization.verification_uri,
|
|
@@ -1802,7 +1808,7 @@ async function apiRequest(apiPath, options = {}, baseUrlOverride) {
|
|
|
1802
1808
|
: selectWorkbenchBaseUrl({ configBaseUrl: config.baseUrl });
|
|
1803
1809
|
const token = await workbenchCloudToken({ baseUrl });
|
|
1804
1810
|
const method = options.method ?? "GET";
|
|
1805
|
-
const canRetry = method
|
|
1811
|
+
const canRetry = isIdempotentApiRequestMethod(method);
|
|
1806
1812
|
const requestBody = encodeJsonRequestBody(options.body);
|
|
1807
1813
|
let lastError = null;
|
|
1808
1814
|
for (let attempt = 1; attempt <= API_REQUEST_MAX_ATTEMPTS; attempt += 1) {
|
|
@@ -1977,6 +1983,9 @@ function isTransientFetchError(error) {
|
|
|
1977
1983
|
function isTransientApiRequestError(error) {
|
|
1978
1984
|
return error instanceof WorkbenchApiRequestError && (error.status === 429 || error.status >= 500);
|
|
1979
1985
|
}
|
|
1986
|
+
function isIdempotentApiRequestMethod(method) {
|
|
1987
|
+
return method === "GET" || method === "PUT" || method === "DELETE";
|
|
1988
|
+
}
|
|
1980
1989
|
function errorMessage(error) {
|
|
1981
1990
|
return error instanceof Error ? error.message : String(error);
|
|
1982
1991
|
}
|
|
@@ -2748,11 +2757,6 @@ function snapshotHasWorkflowCase(snapshot) {
|
|
|
2748
2757
|
/^\.workbench\/cases\/[^/]+\/case\.ya?ml$/u.test(file.path)) ?? [];
|
|
2749
2758
|
return caseFiles.some((file) => file.kind === "text" && !/\n\s*smoke:\s*true(?:\s|$)/u.test(`\n${file.content}`));
|
|
2750
2759
|
}
|
|
2751
|
-
function installHandleFromStatusRemote(remote) {
|
|
2752
|
-
const publicationUrl = remote.publication.status === "published" ? remote.publication.installUrl : undefined;
|
|
2753
|
-
const source = parseWorkbenchInstallSource(publicationUrl ?? remote.url);
|
|
2754
|
-
return source ? `${source.owner}/${source.skill}` : publicationUrl ?? remote.url;
|
|
2755
|
-
}
|
|
2756
2760
|
async function statusWithCausalNext(status, auth, core, machine) {
|
|
2757
2761
|
if (!status.project.initialized) {
|
|
2758
2762
|
return {
|
|
@@ -2803,19 +2807,59 @@ async function statusWithCausalNext(status, auth, core, machine) {
|
|
|
2803
2807
|
currentVersionId !== undefined &&
|
|
2804
2808
|
remote.publication.versionId !== currentVersionId);
|
|
2805
2809
|
if (canPublish && stalePublishedCloudRemote) {
|
|
2810
|
+
const publishedVersionId = stalePublishedCloudRemote.publication.versionId;
|
|
2811
|
+
if (snapshot && publishedVersionId && currentVersionId) {
|
|
2812
|
+
if (versionHasAncestor(snapshot, currentVersionId, publishedVersionId)) {
|
|
2813
|
+
return { ...status, next: "workbench publish" };
|
|
2814
|
+
}
|
|
2815
|
+
if (versionHasAncestor(snapshot, publishedVersionId, currentVersionId)) {
|
|
2816
|
+
return { ...status, next: `workbench switch ${displayRef(publishedVersionId)}` };
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2806
2819
|
return { ...status, next: "workbench publish" };
|
|
2807
2820
|
}
|
|
2808
|
-
const publishedCloudRemote = status.remotes.find((remote) => remote.kind === "workbench-cloud" &&
|
|
2809
|
-
remote.publication.status === "published" &&
|
|
2810
|
-
Boolean(remote.publication.installUrl));
|
|
2811
|
-
if (publishedCloudRemote) {
|
|
2812
|
-
return { ...status, next: `workbench install ${installHandleFromStatusRemote(publishedCloudRemote)}` };
|
|
2813
|
-
}
|
|
2814
2821
|
return {
|
|
2815
2822
|
...status,
|
|
2816
2823
|
next: null,
|
|
2817
2824
|
};
|
|
2818
2825
|
}
|
|
2826
|
+
function versionHasAncestor(snapshot, versionId, ancestorId) {
|
|
2827
|
+
if (versionId === ancestorId) {
|
|
2828
|
+
return true;
|
|
2829
|
+
}
|
|
2830
|
+
const parentsByChild = new Map();
|
|
2831
|
+
for (const edge of snapshot.lineage) {
|
|
2832
|
+
const parents = parentsByChild.get(edge.childId) ?? [];
|
|
2833
|
+
parents.push(edge.parentId);
|
|
2834
|
+
parentsByChild.set(edge.childId, parents);
|
|
2835
|
+
}
|
|
2836
|
+
for (const version of snapshot.versions) {
|
|
2837
|
+
if (version.parentIds.length === 0) {
|
|
2838
|
+
continue;
|
|
2839
|
+
}
|
|
2840
|
+
const parents = parentsByChild.get(version.id) ?? [];
|
|
2841
|
+
for (const parentId of version.parentIds) {
|
|
2842
|
+
if (!parents.includes(parentId)) {
|
|
2843
|
+
parents.push(parentId);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
parentsByChild.set(version.id, parents);
|
|
2847
|
+
}
|
|
2848
|
+
const seen = new Set();
|
|
2849
|
+
const stack = [...(parentsByChild.get(versionId) ?? [])];
|
|
2850
|
+
while (stack.length > 0) {
|
|
2851
|
+
const next = stack.pop();
|
|
2852
|
+
if (next === ancestorId) {
|
|
2853
|
+
return true;
|
|
2854
|
+
}
|
|
2855
|
+
if (seen.has(next)) {
|
|
2856
|
+
continue;
|
|
2857
|
+
}
|
|
2858
|
+
seen.add(next);
|
|
2859
|
+
stack.push(...(parentsByChild.get(next) ?? []));
|
|
2860
|
+
}
|
|
2861
|
+
return false;
|
|
2862
|
+
}
|
|
2819
2863
|
function displayRef(id) {
|
|
2820
2864
|
const version = /^v_([0-9a-f]{8,})$/iu.exec(id);
|
|
2821
2865
|
if (version?.[1]) {
|
|
@@ -3206,7 +3250,21 @@ async function evalSuccessNextCommand(core, runs) {
|
|
|
3206
3250
|
return "edit .workbench/cases, then run workbench eval";
|
|
3207
3251
|
}
|
|
3208
3252
|
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(core);
|
|
3209
|
-
|
|
3253
|
+
if (!snapshotHasWorkflowCase(snapshot)) {
|
|
3254
|
+
return "edit .workbench/cases, then run workbench eval";
|
|
3255
|
+
}
|
|
3256
|
+
const auth = await workbenchCliAuthStatus();
|
|
3257
|
+
if (auth.workbenchCloud.status !== "authenticated") {
|
|
3258
|
+
return "workbench login";
|
|
3259
|
+
}
|
|
3260
|
+
const status = await workbenchStatusSnapshot(core);
|
|
3261
|
+
return statusHasPublishedCurrentCloudSource(status) ? null : "workbench publish";
|
|
3262
|
+
}
|
|
3263
|
+
function statusHasPublishedCurrentCloudSource(status) {
|
|
3264
|
+
const currentVersionId = status.project.currentVersionId;
|
|
3265
|
+
return Boolean(currentVersionId && status.remotes.some((remote) => remote.kind === "workbench-cloud" &&
|
|
3266
|
+
remote.publication.status === "published" &&
|
|
3267
|
+
remote.publication.versionId === currentVersionId));
|
|
3210
3268
|
}
|
|
3211
3269
|
function formatStatusSnapshot(status) {
|
|
3212
3270
|
const lines = [
|
|
@@ -3315,7 +3373,8 @@ function formatJob(job) {
|
|
|
3315
3373
|
}
|
|
3316
3374
|
function formatComparison(comparison) {
|
|
3317
3375
|
const lines = ["version\tskill\tagent\tstatus\tscore\tcost\tlatency\trun"];
|
|
3318
|
-
|
|
3376
|
+
const evidenceCells = comparison.cells.filter((cell) => cell.runId || cell.status);
|
|
3377
|
+
for (const cell of evidenceCells) {
|
|
3319
3378
|
lines.push([
|
|
3320
3379
|
displayRef(cell.versionId),
|
|
3321
3380
|
cell.skillName,
|
|
@@ -3327,7 +3386,73 @@ function formatComparison(comparison) {
|
|
|
3327
3386
|
cell.runId ? displayRef(cell.runId) : "n/a",
|
|
3328
3387
|
].join("\t"));
|
|
3329
3388
|
}
|
|
3330
|
-
return lines.join("\n");
|
|
3389
|
+
return lines.length === 1 ? "No comparable runs." : lines.join("\n");
|
|
3390
|
+
}
|
|
3391
|
+
function formatDiff(entries) {
|
|
3392
|
+
if (entries.length === 0) {
|
|
3393
|
+
return "No diff.";
|
|
3394
|
+
}
|
|
3395
|
+
return entries.map(formatDiffEntry).join("\n");
|
|
3396
|
+
}
|
|
3397
|
+
function formatDiffEntry(entry) {
|
|
3398
|
+
const before = entry.before ?? "";
|
|
3399
|
+
const after = entry.after ?? "";
|
|
3400
|
+
if (entry.status === "modified" || entry.status === "added" || entry.status === "removed") {
|
|
3401
|
+
return [
|
|
3402
|
+
`diff --workbench ${entry.path}`,
|
|
3403
|
+
`--- ${entry.status === "added" ? "/dev/null" : `a/${entry.path}`}`,
|
|
3404
|
+
`+++ ${entry.status === "removed" ? "/dev/null" : `b/${entry.path}`}`,
|
|
3405
|
+
...unifiedLineDiff(before, after),
|
|
3406
|
+
].join("\n");
|
|
3407
|
+
}
|
|
3408
|
+
return `${entry.status}\t${entry.path}`;
|
|
3409
|
+
}
|
|
3410
|
+
function unifiedLineDiff(before, after) {
|
|
3411
|
+
const beforeLines = splitDiffLines(before);
|
|
3412
|
+
const afterLines = splitDiffLines(after);
|
|
3413
|
+
const table = longestCommonSubsequenceTable(beforeLines, afterLines);
|
|
3414
|
+
const lines = [];
|
|
3415
|
+
let left = 0;
|
|
3416
|
+
let right = 0;
|
|
3417
|
+
while (left < beforeLines.length && right < afterLines.length) {
|
|
3418
|
+
if (beforeLines[left] === afterLines[right]) {
|
|
3419
|
+
lines.push(` ${beforeLines[left]}`);
|
|
3420
|
+
left += 1;
|
|
3421
|
+
right += 1;
|
|
3422
|
+
}
|
|
3423
|
+
else if (table[left + 1][right] >= table[left][right + 1]) {
|
|
3424
|
+
lines.push(`-${beforeLines[left]}`);
|
|
3425
|
+
left += 1;
|
|
3426
|
+
}
|
|
3427
|
+
else {
|
|
3428
|
+
lines.push(`+${afterLines[right]}`);
|
|
3429
|
+
right += 1;
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
while (left < beforeLines.length) {
|
|
3433
|
+
lines.push(`-${beforeLines[left]}`);
|
|
3434
|
+
left += 1;
|
|
3435
|
+
}
|
|
3436
|
+
while (right < afterLines.length) {
|
|
3437
|
+
lines.push(`+${afterLines[right]}`);
|
|
3438
|
+
right += 1;
|
|
3439
|
+
}
|
|
3440
|
+
return lines.length > 0 ? lines : [" "];
|
|
3441
|
+
}
|
|
3442
|
+
function splitDiffLines(value) {
|
|
3443
|
+
const withoutFinalNewline = value.endsWith("\n") ? value.slice(0, -1) : value;
|
|
3444
|
+
return withoutFinalNewline ? withoutFinalNewline.split(/\r?\n/u) : [];
|
|
3445
|
+
}
|
|
3446
|
+
function longestCommonSubsequenceTable(left, right) {
|
|
3447
|
+
const table = Array.from({ length: left.length + 1 }, () => Array.from({ length: right.length + 1 }, () => 0));
|
|
3448
|
+
for (let i = left.length - 1; i >= 0; i -= 1) {
|
|
3449
|
+
for (let j = right.length - 1; j >= 0; j -= 1) {
|
|
3450
|
+
table[i][j] = left[i] === right[j]
|
|
3451
|
+
? table[i + 1][j + 1] + 1
|
|
3452
|
+
: Math.max(table[i + 1][j], table[i][j + 1]);
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
return table;
|
|
3331
3456
|
}
|
|
3332
3457
|
function shortObjectId(id) {
|
|
3333
3458
|
return id.length > 8 ? id.slice(0, 8) : id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-ai/workbench",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.79",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/workbench-ai/workbench.git",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"skills": "1.5.11",
|
|
24
24
|
"yaml": "^2.8.2",
|
|
25
|
-
"@workbench-ai/workbench-built-in-adapters": "0.0.
|
|
26
|
-
"@workbench-ai/workbench-core": "0.0.
|
|
27
|
-
"@workbench-ai/workbench-contract": "0.0.
|
|
28
|
-
"@workbench-ai/workbench-protocol": "0.0.
|
|
25
|
+
"@workbench-ai/workbench-built-in-adapters": "0.0.79",
|
|
26
|
+
"@workbench-ai/workbench-core": "0.0.79",
|
|
27
|
+
"@workbench-ai/workbench-contract": "0.0.79",
|
|
28
|
+
"@workbench-ai/workbench-protocol": "0.0.79"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@tailwindcss/postcss": "^4.2.2",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"react-dom": "^19.2.0",
|
|
37
37
|
"typescript": "^5.9.2",
|
|
38
38
|
"vitest": "^3.2.4",
|
|
39
|
-
"@workbench-ai/workbench-ui": "0.0.
|
|
39
|
+
"@workbench-ai/workbench-ui": "0.0.79"
|
|
40
40
|
},
|
|
41
41
|
"scripts": {
|
|
42
42
|
"build": "rm -rf dist && tsc -p tsconfig.json && chmod 755 dist/workbench.js && node ./scripts/build-dev-open-assets.mjs",
|