@workbench-ai/workbench 0.0.71 → 0.0.73
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 +299 -76
- 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":"AA2DA,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC/B;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2DA,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;CAC/B;AAsUD,wBAAsB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAE,KAGzD,GAAG,OAAO,CAAC,MAAM,CAAC,CAiMlB"}
|
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ const HELP_ALL = [
|
|
|
44
44
|
" workbench show REF[:PATH] [--json]",
|
|
45
45
|
" workbench diff [A..B] [--json]",
|
|
46
46
|
" workbench switch VERSION [--json]",
|
|
47
|
-
" workbench open [--host HOST] [--port PORT] [--no-open]
|
|
47
|
+
" workbench open [--host HOST] [--port PORT] [--no-open]",
|
|
48
48
|
"",
|
|
49
49
|
"Configure:",
|
|
50
50
|
" workbench case add RUN_ID [--json]",
|
|
@@ -162,9 +162,9 @@ const COMMAND_HELP = {
|
|
|
162
162
|
].join("\n"),
|
|
163
163
|
open: [
|
|
164
164
|
"Usage:",
|
|
165
|
-
" workbench open [--host HOST] [--port PORT] [--no-open]
|
|
165
|
+
" workbench open [--host HOST] [--port PORT] [--no-open]",
|
|
166
166
|
"",
|
|
167
|
-
"Serves
|
|
167
|
+
"Serves the read-only Workbench inspection UI.",
|
|
168
168
|
"",
|
|
169
169
|
"Example:",
|
|
170
170
|
" workbench open --no-open",
|
|
@@ -221,9 +221,12 @@ const COMMAND_HELP = {
|
|
|
221
221
|
const COMMON_FLAGS = {
|
|
222
222
|
json: "boolean",
|
|
223
223
|
};
|
|
224
|
+
const DIR_FLAG = {
|
|
225
|
+
dir: "string",
|
|
226
|
+
};
|
|
224
227
|
const PROJECT_FLAGS = {
|
|
225
228
|
...COMMON_FLAGS,
|
|
226
|
-
|
|
229
|
+
...DIR_FLAG,
|
|
227
230
|
};
|
|
228
231
|
const HELP_FLAG = {
|
|
229
232
|
help: "boolean",
|
|
@@ -270,7 +273,7 @@ const COMMAND_FLAGS = {
|
|
|
270
273
|
},
|
|
271
274
|
logout: { ...COMMON_FLAGS, ...HELP_FLAG },
|
|
272
275
|
new: { ...PROJECT_FLAGS, ...HELP_FLAG },
|
|
273
|
-
open: { ...
|
|
276
|
+
open: { ...DIR_FLAG, ...HELP_FLAG, host: "string", "no-open": "boolean", port: "port" },
|
|
274
277
|
publish: {
|
|
275
278
|
...PROJECT_FLAGS,
|
|
276
279
|
...HELP_FLAG,
|
|
@@ -359,13 +362,16 @@ export async function runCli(argv, io = {
|
|
|
359
362
|
return emitEvalFailure(runs, failedRuns, artifactIds, parsed, io);
|
|
360
363
|
}
|
|
361
364
|
const deltas = await evalDeltas(core, runs);
|
|
365
|
+
const coverage = await evalCoverageSummaries(core, runs);
|
|
362
366
|
const next = await evalSuccessNextCommand(core, runs);
|
|
363
367
|
return emitResult("workbench.cli.eval.v1", {
|
|
364
368
|
result: runs.map((run) => runSummary(run, artifactIds.get(run.id) ?? [])),
|
|
369
|
+
coverage: coverage,
|
|
365
370
|
deltas: deltas,
|
|
366
371
|
next: next,
|
|
367
372
|
}, parsed, io, () => [
|
|
368
373
|
runs.map(formatRun).join("\n"),
|
|
374
|
+
...coverage.map(formatEvalCoverage),
|
|
369
375
|
...deltas.map(formatEvalDelta),
|
|
370
376
|
...(next ? [`next: ${next}`] : []),
|
|
371
377
|
].filter(Boolean).join("\n"));
|
|
@@ -449,10 +455,7 @@ export async function runCli(argv, io = {
|
|
|
449
455
|
pinnedInstallUrl: preview.pinnedInstallUrl,
|
|
450
456
|
dryRun: true,
|
|
451
457
|
}, parsed, io, () => [
|
|
452
|
-
`Would publish ${displayRef(preview.version.id)}
|
|
453
|
-
`Visibility: ${preview.visibility}`,
|
|
454
|
-
`Install: ${preview.installUrl}`,
|
|
455
|
-
`Pinned: ${preview.pinnedInstallUrl}`,
|
|
458
|
+
`Would publish ${displayRef(preview.version.id)} as ${preview.installHandle} (${preview.visibility}).`,
|
|
456
459
|
`next: workbench install ${preview.installHandle}`,
|
|
457
460
|
].join("\n"));
|
|
458
461
|
}
|
|
@@ -473,25 +476,18 @@ export async function runCli(argv, io = {
|
|
|
473
476
|
pinnedInstallUrl: result.pinnedInstallUrl,
|
|
474
477
|
...(result.dryRun ? { dryRun: true } : {}),
|
|
475
478
|
}, parsed, io, () => [
|
|
476
|
-
`${result.dryRun ? "Would publish" : "Published"} ${displayRef(result.version.id)}
|
|
477
|
-
`Visibility: ${result.visibility}`,
|
|
478
|
-
`Install: ${result.installUrl}`,
|
|
479
|
-
`Pinned: ${result.pinnedInstallUrl}`,
|
|
479
|
+
`${result.dryRun ? "Would publish" : "Published"} ${displayRef(result.version.id)} as ${result.installHandle} (${result.visibility}).`,
|
|
480
480
|
`next: workbench install ${result.installHandle}`,
|
|
481
481
|
].join("\n"));
|
|
482
482
|
}
|
|
483
483
|
if (command === "open") {
|
|
484
|
-
if (parsed.flags.json === true) {
|
|
485
|
-
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(core);
|
|
486
|
-
return output(manifestOnly(snapshot), parsed, io, () => "Read-only Workbench inspection data is available with --json.");
|
|
487
|
-
}
|
|
488
484
|
// The browser server serves committed object state through a read-only
|
|
489
485
|
// snapshot path, so long-running commands do not block page loads.
|
|
490
486
|
const server = await startWorkbenchOpenServer({
|
|
491
487
|
dir: dirFlag(parsed),
|
|
492
488
|
authToken: core.authToken,
|
|
493
489
|
host: stringFlag(parsed, "host"),
|
|
494
|
-
port:
|
|
490
|
+
port: portFlag(parsed, "port"),
|
|
495
491
|
});
|
|
496
492
|
io.stdout.write(`Workbench: ${server.url}\n`);
|
|
497
493
|
if (parsed.flags["no-open"] !== true) {
|
|
@@ -506,9 +502,10 @@ export async function runCli(argv, io = {
|
|
|
506
502
|
}
|
|
507
503
|
}
|
|
508
504
|
async function handleStatus(parsed, io) {
|
|
509
|
-
const
|
|
505
|
+
const core = await coreOptions(parsed);
|
|
506
|
+
const status = await workbenchStatusSnapshot(core);
|
|
510
507
|
const auth = await workbenchCliAuthStatus();
|
|
511
|
-
const cliStatus = statusWithCausalNext(status, auth);
|
|
508
|
+
const cliStatus = await statusWithCausalNext(status, auth, core);
|
|
512
509
|
return emitResult("workbench.status.v1", {
|
|
513
510
|
project: cliStatus.project,
|
|
514
511
|
worktree: cliStatus.worktree,
|
|
@@ -557,7 +554,7 @@ async function handleLog(parsed, io) {
|
|
|
557
554
|
versionId: run.versionId,
|
|
558
555
|
skillName: run.skillName,
|
|
559
556
|
agentName: run.agentName,
|
|
560
|
-
...(run
|
|
557
|
+
...(scoredRunValue(run) !== undefined ? { score: scoredRunValue(run) } : {}),
|
|
561
558
|
})) : []),
|
|
562
559
|
].sort((left, right) => right.createdAt.localeCompare(left.createdAt));
|
|
563
560
|
return emitResult("workbench.cli.log.v1", {
|
|
@@ -597,7 +594,7 @@ async function handleShow(parsed, io) {
|
|
|
597
594
|
const evidenceFiles = evidenceFilesForRunOrJob(snapshot, objectRef);
|
|
598
595
|
if (details.length > 0 || evidenceFiles.length > 0) {
|
|
599
596
|
return output({
|
|
600
|
-
details: details,
|
|
597
|
+
details: details.map(evidenceDetailSummary),
|
|
601
598
|
files: evidenceFiles.map(fileSummary),
|
|
602
599
|
}, parsed, io, () => formatRunOrJobEvidence(details, evidenceFiles));
|
|
603
600
|
}
|
|
@@ -733,11 +730,14 @@ function validateFlagValue(name, value, kind) {
|
|
|
733
730
|
if (typeof value !== "string" || !value.trim()) {
|
|
734
731
|
throw new WorkbenchUserError(`--${name} requires a value.`);
|
|
735
732
|
}
|
|
736
|
-
if (kind === "positive-integer") {
|
|
733
|
+
if (kind === "positive-integer" || kind === "port") {
|
|
737
734
|
const parsedValue = Number(value);
|
|
738
|
-
if (!Number.isInteger(parsedValue) || parsedValue <= 0) {
|
|
735
|
+
if (kind === "positive-integer" && (!Number.isInteger(parsedValue) || parsedValue <= 0)) {
|
|
739
736
|
throw new WorkbenchUserError(`--${name} must be a positive integer.`);
|
|
740
737
|
}
|
|
738
|
+
if (kind === "port" && (!Number.isInteger(parsedValue) || parsedValue < 0 || parsedValue > 65535)) {
|
|
739
|
+
throw new WorkbenchUserError(`--${name} must be an integer between 0 and 65535.`);
|
|
740
|
+
}
|
|
741
741
|
}
|
|
742
742
|
}
|
|
743
743
|
const CONFIG_SCHEMA = "workbench.cli.config.v1";
|
|
@@ -926,8 +926,22 @@ async function handleInstall(parsed, io) {
|
|
|
926
926
|
].join("\n"));
|
|
927
927
|
}
|
|
928
928
|
async function handleCloudEval(parsed, io) {
|
|
929
|
-
const started = await startCloudExecution("eval", parsed);
|
|
929
|
+
const started = await startCloudExecution("eval", parsed, io);
|
|
930
930
|
const artifactIds = await artifactIdsByRunId(started.core, started.runs);
|
|
931
|
+
if (started.detached) {
|
|
932
|
+
const next = cloudDetachedNextCommand(started.runs);
|
|
933
|
+
emitResult("workbench.cli.eval.v1", {
|
|
934
|
+
result: started.runs.map((run) => runSummary(run, artifactIds.get(run.id) ?? [])),
|
|
935
|
+
detached: true,
|
|
936
|
+
next: next,
|
|
937
|
+
cloud: cloudExecutionSummary(started),
|
|
938
|
+
}, parsed, io, () => [
|
|
939
|
+
`Detached from hosted eval on ${started.remote.url}.`,
|
|
940
|
+
started.runs.map(formatRun).join("\n"),
|
|
941
|
+
...(next ? [`next: ${next}`] : []),
|
|
942
|
+
].filter(Boolean).join("\n"));
|
|
943
|
+
return 130;
|
|
944
|
+
}
|
|
931
945
|
const failedRuns = started.runs.filter((run) => run.status === "failed" || run.status === "canceled");
|
|
932
946
|
if (failedRuns.length > 0) {
|
|
933
947
|
return emitEvalFailure(started.runs, failedRuns, artifactIds, parsed, io);
|
|
@@ -947,8 +961,22 @@ async function handleCloudEval(parsed, io) {
|
|
|
947
961
|
].filter(Boolean).join("\n"));
|
|
948
962
|
}
|
|
949
963
|
async function handleCloudImprove(parsed, io) {
|
|
950
|
-
const started = await startCloudExecution("improve", parsed);
|
|
964
|
+
const started = await startCloudExecution("improve", parsed, io);
|
|
951
965
|
const artifactIds = await artifactIdsByRunId(started.core, started.runs);
|
|
966
|
+
if (started.detached) {
|
|
967
|
+
const next = cloudDetachedNextCommand(started.runs);
|
|
968
|
+
emitResult("workbench.cli.improve.v1", {
|
|
969
|
+
result: started.runs.map((run) => runSummary(run, artifactIds.get(run.id) ?? [])),
|
|
970
|
+
detached: true,
|
|
971
|
+
next: next,
|
|
972
|
+
cloud: cloudExecutionSummary(started),
|
|
973
|
+
}, parsed, io, () => [
|
|
974
|
+
`Detached from hosted improve on ${started.remote.url}.`,
|
|
975
|
+
started.runs.map(formatRun).join("\n"),
|
|
976
|
+
...(next ? [`next: ${next}`] : []),
|
|
977
|
+
].filter(Boolean).join("\n"));
|
|
978
|
+
return 130;
|
|
979
|
+
}
|
|
952
980
|
const failedRuns = started.runs.filter((run) => run.status === "failed" || run.status === "canceled");
|
|
953
981
|
if (failedRuns.length > 0) {
|
|
954
982
|
const first = failedRuns[0];
|
|
@@ -1014,8 +1042,9 @@ async function pathExists(filePath) {
|
|
|
1014
1042
|
return false;
|
|
1015
1043
|
}
|
|
1016
1044
|
}
|
|
1017
|
-
async function startCloudExecution(command, parsed) {
|
|
1045
|
+
async function startCloudExecution(command, parsed, io) {
|
|
1018
1046
|
const root = dirFlag(parsed) ?? process.cwd();
|
|
1047
|
+
const showProgress = parsed.flags.json !== true;
|
|
1019
1048
|
const remote = await ensureCloudRemoteForExecution(root, parsed);
|
|
1020
1049
|
const source = parseWorkbenchInstallSource(remote.url);
|
|
1021
1050
|
if (!source) {
|
|
@@ -1033,7 +1062,9 @@ async function startCloudExecution(command, parsed) {
|
|
|
1033
1062
|
});
|
|
1034
1063
|
}
|
|
1035
1064
|
const core = { dir: root, authToken: token };
|
|
1065
|
+
writeCloudProgress(io, `workbench cloud: syncing ${remote.name} before hosted ${command}.`, showProgress);
|
|
1036
1066
|
const syncBefore = await syncWorkbenchRemote({ ...core, remote: remote.name });
|
|
1067
|
+
writeCloudProgress(io, `workbench cloud: synced ${remote.name} before hosted ${command} (pushed=${syncBefore.pushed}, pulled=${syncBefore.pulled}, up-to-date=${syncBefore.upToDate}).`, showProgress);
|
|
1037
1068
|
const startSnapshot = await createWorkbenchReadOnlyInspectionSnapshot(core);
|
|
1038
1069
|
const skillId = await resolveCloudSkillId(source);
|
|
1039
1070
|
const response = await apiRequest(`/api/workbench/skills/${encodeURIComponent(skillId)}${command === "improve" ? "/improve" : "/runs"}`, { method: "POST", body: cloudExecutionRequestBody(command, parsed) }, source.baseUrl);
|
|
@@ -1046,9 +1077,16 @@ async function startCloudExecution(command, parsed) {
|
|
|
1046
1077
|
exitCode: 1,
|
|
1047
1078
|
});
|
|
1048
1079
|
}
|
|
1080
|
+
const initialRunIds = runs.map((run) => run.id);
|
|
1081
|
+
writeCloudProgress(io, `workbench cloud: scheduled hosted ${command} on ${remote.url} (${formatCloudRunStatuses(runs)}).`, showProgress);
|
|
1049
1082
|
const initialSyncAfter = await syncWorkbenchRemote({ ...core, remote: remote.name });
|
|
1083
|
+
writeCloudProgress(io, `workbench cloud: synced after scheduling hosted ${command} (pushed=${initialSyncAfter.pushed}, pulled=${initialSyncAfter.pulled}, up-to-date=${initialSyncAfter.upToDate}).`, showProgress);
|
|
1084
|
+
writeCloudProgress(io, `workbench cloud: waiting for terminal status; press Ctrl-C to detach and resume with workbench status or workbench show ${displayRef(initialRunIds[0] ?? "run")}.`, showProgress);
|
|
1050
1085
|
const completed = await waitForCloudRuns({
|
|
1086
|
+
command,
|
|
1051
1087
|
core,
|
|
1088
|
+
io,
|
|
1089
|
+
progress: showProgress,
|
|
1052
1090
|
remote,
|
|
1053
1091
|
runs,
|
|
1054
1092
|
initialSync: initialSyncAfter,
|
|
@@ -1057,7 +1095,9 @@ async function startCloudExecution(command, parsed) {
|
|
|
1057
1095
|
core,
|
|
1058
1096
|
remote,
|
|
1059
1097
|
skillId,
|
|
1098
|
+
initialRunIds,
|
|
1060
1099
|
runs: completed.runs,
|
|
1100
|
+
...(completed.detached ? { detached: true } : {}),
|
|
1061
1101
|
startVersionId: startSnapshot.status.currentVersionId ?? startSnapshot.refs.current,
|
|
1062
1102
|
source,
|
|
1063
1103
|
sync: {
|
|
@@ -1081,27 +1121,59 @@ async function waitForCloudRuns(input) {
|
|
|
1081
1121
|
const timeoutMs = positiveIntEnv("WORKBENCH_CLOUD_RUN_TIMEOUT_MS") ?? CLOUD_RUN_TIMEOUT_MS;
|
|
1082
1122
|
const pollIntervalMs = positiveIntEnv("WORKBENCH_CLOUD_RUN_POLL_INTERVAL_MS") ?? CLOUD_RUN_POLL_INTERVAL_MS;
|
|
1083
1123
|
const deadline = Date.now() + timeoutMs;
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
}
|
|
1124
|
+
let runs = [...input.runs];
|
|
1125
|
+
let interrupted = false;
|
|
1126
|
+
const onSigint = () => {
|
|
1127
|
+
interrupted = true;
|
|
1128
|
+
writeCloudProgress(input.io, `workbench cloud: detaching from hosted ${input.command} (${runIds.map(displayRef).join(", ")}).`, input.progress);
|
|
1129
|
+
};
|
|
1130
|
+
process.once("SIGINT", onSigint);
|
|
1131
|
+
const seenStatuses = new Map();
|
|
1132
|
+
try {
|
|
1133
|
+
while (true) {
|
|
1134
|
+
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(input.core);
|
|
1135
|
+
const snapshotRuns = runIds
|
|
1136
|
+
.map((id) => snapshot.runs.find((entry) => entry.id === id))
|
|
1137
|
+
.filter((run) => Boolean(run));
|
|
1138
|
+
if (snapshotRuns.length > 0) {
|
|
1139
|
+
runs = runIds.map((id) => snapshotRuns.find((entry) => entry.id === id) ?? runs.find((entry) => entry.id === id))
|
|
1140
|
+
.filter((run) => Boolean(run));
|
|
1141
|
+
}
|
|
1142
|
+
for (const run of runs) {
|
|
1143
|
+
const previous = seenStatuses.get(run.id);
|
|
1144
|
+
if (previous !== run.status) {
|
|
1145
|
+
seenStatuses.set(run.id, run.status);
|
|
1146
|
+
writeCloudProgress(input.io, `workbench cloud: ${displayRef(run.id)} is ${run.status}.`, input.progress);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (runs.length === runIds.length && runs.every(isTerminalRun)) {
|
|
1150
|
+
writeCloudProgress(input.io, `workbench cloud: hosted ${input.command} finished (${formatCloudRunStatuses(runs)}).`, input.progress);
|
|
1151
|
+
return { runs, sync };
|
|
1152
|
+
}
|
|
1153
|
+
if (interrupted) {
|
|
1154
|
+
return { runs, sync, detached: true };
|
|
1155
|
+
}
|
|
1156
|
+
if (Date.now() >= deadline) {
|
|
1157
|
+
throw new WorkbenchCodedError("cloud_run_pending", "Hosted Workbench run is still running.", {
|
|
1158
|
+
retryable: true,
|
|
1159
|
+
remediation: runIds[0] ? `Run workbench show ${runIds[0]}.` : "Run workbench log --runs.",
|
|
1160
|
+
subject: {
|
|
1161
|
+
runIds,
|
|
1162
|
+
statuses: Object.fromEntries(runs.map((run) => [run.id, run.status])),
|
|
1163
|
+
},
|
|
1164
|
+
exitCode: 1,
|
|
1165
|
+
});
|
|
1166
|
+
}
|
|
1167
|
+
await sleep(pollIntervalMs);
|
|
1168
|
+
if (interrupted) {
|
|
1169
|
+
return { runs, sync, detached: true };
|
|
1170
|
+
}
|
|
1171
|
+
sync = await syncWorkbenchRemote({ ...input.core, remote: input.remote.name });
|
|
1172
|
+
writeCloudProgress(input.io, `workbench cloud: synced ${input.remote.name} while waiting (${formatCloudRunStatuses(runs)}).`, input.progress);
|
|
1102
1173
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1174
|
+
}
|
|
1175
|
+
finally {
|
|
1176
|
+
process.off("SIGINT", onSigint);
|
|
1105
1177
|
}
|
|
1106
1178
|
}
|
|
1107
1179
|
function isTerminalRun(run) {
|
|
@@ -1228,6 +1300,10 @@ function cloudExecutionRequestBody(command, parsed) {
|
|
|
1228
1300
|
function cloudImproveNextCommand(runs) {
|
|
1229
1301
|
return cloudExecutionNextCommand(runs, "workbench eval");
|
|
1230
1302
|
}
|
|
1303
|
+
function cloudDetachedNextCommand(runs) {
|
|
1304
|
+
const first = runs[0];
|
|
1305
|
+
return first?.id ? `workbench show ${displayRef(first.id)}` : "workbench status";
|
|
1306
|
+
}
|
|
1231
1307
|
function cloudExecutionNextCommand(runs, successCommand) {
|
|
1232
1308
|
const first = runs[0];
|
|
1233
1309
|
if (!first) {
|
|
@@ -1243,9 +1319,22 @@ function cloudExecutionSummary(started) {
|
|
|
1243
1319
|
remote: started.remote.name,
|
|
1244
1320
|
url: started.remote.url,
|
|
1245
1321
|
skillId: started.skillId,
|
|
1322
|
+
initialRunIds: started.initialRunIds,
|
|
1323
|
+
...(started.detached ? { detached: true } : {}),
|
|
1246
1324
|
sync: started.sync,
|
|
1247
1325
|
};
|
|
1248
1326
|
}
|
|
1327
|
+
function writeCloudProgress(io, message, enabled = true) {
|
|
1328
|
+
if (!enabled) {
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
io.stderr.write(`${message}\n`);
|
|
1332
|
+
}
|
|
1333
|
+
function formatCloudRunStatuses(runs) {
|
|
1334
|
+
return runs.length > 0
|
|
1335
|
+
? runs.map((run) => `${displayRef(run.id)}:${run.status}`).join(", ")
|
|
1336
|
+
: "no runs";
|
|
1337
|
+
}
|
|
1249
1338
|
function workbenchInstallSourceSummary(source, snapshot) {
|
|
1250
1339
|
const installUrl = `${source.baseUrl}/skills/${encodeURIComponent(source.owner)}/${encodeURIComponent(source.skill)}`;
|
|
1251
1340
|
return {
|
|
@@ -2204,6 +2293,17 @@ function intFlag(parsed, name) {
|
|
|
2204
2293
|
}
|
|
2205
2294
|
return parsedValue;
|
|
2206
2295
|
}
|
|
2296
|
+
function portFlag(parsed, name) {
|
|
2297
|
+
const value = stringFlag(parsed, name);
|
|
2298
|
+
if (!value) {
|
|
2299
|
+
return undefined;
|
|
2300
|
+
}
|
|
2301
|
+
const parsedValue = Number(value);
|
|
2302
|
+
if (!Number.isInteger(parsedValue) || parsedValue < 0 || parsedValue > 65535) {
|
|
2303
|
+
throw new WorkbenchUserError(`--${name} must be an integer between 0 and 65535.`);
|
|
2304
|
+
}
|
|
2305
|
+
return parsedValue;
|
|
2306
|
+
}
|
|
2207
2307
|
function optionalPositional(parsed, index) {
|
|
2208
2308
|
return parsed.positionals[index];
|
|
2209
2309
|
}
|
|
@@ -2452,7 +2552,7 @@ function runSummary(run, artifactIds) {
|
|
|
2452
2552
|
versionId: run.versionId,
|
|
2453
2553
|
skillName: run.skillName,
|
|
2454
2554
|
agentName: run.agentName,
|
|
2455
|
-
...(run
|
|
2555
|
+
...(scoredRunValue(run) !== undefined ? { score: scoredRunValue(run) } : {}),
|
|
2456
2556
|
...(run.latencyMs !== undefined ? { latencyMs: run.latencyMs } : {}),
|
|
2457
2557
|
...(run.error ? { error: run.error } : {}),
|
|
2458
2558
|
...(run.jobIds ? { jobIds: run.jobIds } : {}),
|
|
@@ -2467,7 +2567,7 @@ function runFailureSummary(run, artifactIds) {
|
|
|
2467
2567
|
skill: run.skillName,
|
|
2468
2568
|
status: run.status,
|
|
2469
2569
|
versionId: run.versionId,
|
|
2470
|
-
...(run
|
|
2570
|
+
...(scoredRunValue(run) !== undefined ? { score: scoredRunValue(run) } : {}),
|
|
2471
2571
|
...(run.error ? { error: run.error } : {}),
|
|
2472
2572
|
traceIds: run.traceIds,
|
|
2473
2573
|
artifactIds: [...artifactIds],
|
|
@@ -2511,16 +2611,72 @@ async function workbenchCliAuthStatus() {
|
|
|
2511
2611
|
})),
|
|
2512
2612
|
};
|
|
2513
2613
|
}
|
|
2514
|
-
function
|
|
2614
|
+
function scoredRunValue(run) {
|
|
2615
|
+
return run.status === "succeeded" && typeof run.score === "number" ? run.score : undefined;
|
|
2616
|
+
}
|
|
2617
|
+
function scoredJobValue(job) {
|
|
2618
|
+
return job.status === "succeeded" && typeof job.score === "number" ? job.score : undefined;
|
|
2619
|
+
}
|
|
2620
|
+
function snapshotHasWorkflowCase(snapshot) {
|
|
2621
|
+
const currentVersion = snapshotVersionByRef(snapshot, snapshot.status.currentVersionId ?? snapshot.refs.current ?? "");
|
|
2622
|
+
const caseFiles = currentVersion?.files.filter((file) => file.kind === "text" &&
|
|
2623
|
+
/^\.workbench\/cases\/[^/]+\/case\.ya?ml$/u.test(file.path)) ?? [];
|
|
2624
|
+
return caseFiles.some((file) => file.kind === "text" && !/\n\s*smoke:\s*true(?:\s|$)/u.test(`\n${file.content}`));
|
|
2625
|
+
}
|
|
2626
|
+
function installHandleFromStatusRemote(remote) {
|
|
2627
|
+
const publicationUrl = remote.publication.status === "published" ? remote.publication.installUrl : undefined;
|
|
2628
|
+
const source = parseWorkbenchInstallSource(publicationUrl ?? remote.url);
|
|
2629
|
+
return source ? `${source.owner}/${source.skill}` : publicationUrl ?? remote.url;
|
|
2630
|
+
}
|
|
2631
|
+
async function statusWithCausalNext(status, auth, core) {
|
|
2632
|
+
if (!status.project.initialized) {
|
|
2633
|
+
return status;
|
|
2634
|
+
}
|
|
2635
|
+
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(core).catch(() => null);
|
|
2636
|
+
const lastRun = snapshot?.runs
|
|
2637
|
+
.slice()
|
|
2638
|
+
.sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
|
|
2639
|
+
if ((lastRun?.status === "running" || lastRun?.status === "failed" || lastRun?.status === "canceled") && lastRun.id) {
|
|
2640
|
+
return { ...status, next: `workbench show ${displayRef(lastRun.id)}` };
|
|
2641
|
+
}
|
|
2642
|
+
const failedRemote = status.remotes.find((remote) => remote.sync.status === "error");
|
|
2643
|
+
const hasWorkflowCase = snapshot ? snapshotHasWorkflowCase(snapshot) : false;
|
|
2644
|
+
const hasScoredRun = snapshot?.runs.some((run) => scoredRunValue(run) !== undefined) ?? false;
|
|
2645
|
+
const canPublish = hasWorkflowCase && hasScoredRun;
|
|
2515
2646
|
const cloudAuthMissing = auth.workbenchCloud.status !== "authenticated";
|
|
2516
|
-
const
|
|
2647
|
+
const cloudRemoteNeedsAuth = status.remotes.some((remote) => remote.kind === "workbench-cloud" &&
|
|
2517
2648
|
(remote.sync.status !== "up_to_date" || remote.publication.status === "unpublished"));
|
|
2518
|
-
if (
|
|
2519
|
-
return status;
|
|
2649
|
+
if (cloudAuthMissing && (canPublish || cloudRemoteNeedsAuth)) {
|
|
2650
|
+
return { ...status, next: "workbench login" };
|
|
2651
|
+
}
|
|
2652
|
+
if (failedRemote) {
|
|
2653
|
+
return { ...status, next: `workbench sync ${failedRemote.name}` };
|
|
2654
|
+
}
|
|
2655
|
+
if ((snapshot?.runs.length ?? status.runs.total) === 0) {
|
|
2656
|
+
return { ...status, next: "workbench eval" };
|
|
2657
|
+
}
|
|
2658
|
+
if (!hasWorkflowCase) {
|
|
2659
|
+
return { ...status, next: "edit .workbench/cases, then run workbench eval" };
|
|
2660
|
+
}
|
|
2661
|
+
const cloudRemote = status.remotes.find((remote) => remote.kind === "workbench-cloud");
|
|
2662
|
+
if (canPublish && !cloudRemote) {
|
|
2663
|
+
return { ...status, next: "workbench publish" };
|
|
2664
|
+
}
|
|
2665
|
+
const unpublishedCloudRemote = status.remotes.find((remote) => remote.kind === "workbench-cloud" &&
|
|
2666
|
+
remote.publication.status === "unpublished" &&
|
|
2667
|
+
remote.sync.status === "up_to_date");
|
|
2668
|
+
if (unpublishedCloudRemote) {
|
|
2669
|
+
return { ...status, next: "workbench publish" };
|
|
2670
|
+
}
|
|
2671
|
+
const publishedCloudRemote = status.remotes.find((remote) => remote.kind === "workbench-cloud" &&
|
|
2672
|
+
remote.publication.status === "published" &&
|
|
2673
|
+
Boolean(remote.publication.installUrl));
|
|
2674
|
+
if (publishedCloudRemote) {
|
|
2675
|
+
return { ...status, next: `workbench install ${installHandleFromStatusRemote(publishedCloudRemote)}` };
|
|
2520
2676
|
}
|
|
2521
2677
|
return {
|
|
2522
2678
|
...status,
|
|
2523
|
-
next:
|
|
2679
|
+
next: null,
|
|
2524
2680
|
};
|
|
2525
2681
|
}
|
|
2526
2682
|
function displayRef(id) {
|
|
@@ -2612,16 +2768,16 @@ function evidenceFilesForRunOrJob(snapshot, ref) {
|
|
|
2612
2768
|
const traceById = new Map(snapshot.traces.map((trace) => [trace.id, trace]));
|
|
2613
2769
|
const artifactById = new Map(snapshot.artifacts.map((artifact) => [artifact.id, artifact]));
|
|
2614
2770
|
const files = selection.jobs.flatMap((job) => [
|
|
2615
|
-
...job.traceIds.flatMap((traceId) => {
|
|
2616
|
-
const trace = traceById.get(traceId);
|
|
2617
|
-
return trace
|
|
2618
|
-
? trace.files.map((file) => evidenceFileWithPath(file, `cases/${evidencePathSegment(job.caseId)}/jobs/${evidencePathSegment(job.id)}/traces/${evidencePathSegment(trace.id)}/${file.path}`))
|
|
2619
|
-
: [];
|
|
2620
|
-
}),
|
|
2621
2771
|
...job.artifactIds.flatMap((artifactId) => {
|
|
2622
2772
|
const artifact = artifactById.get(artifactId);
|
|
2623
2773
|
return artifact
|
|
2624
|
-
? artifact.files.map((file) => evidenceFileWithPath(file, `cases/${evidencePathSegment(job.caseId)}/jobs/${evidencePathSegment(job.id)}
|
|
2774
|
+
? artifact.files.filter(isUserFacingEvidenceFile).map((file) => evidenceFileWithPath(file, `cases/${evidencePathSegment(job.caseId)}/jobs/${evidencePathSegment(job.id)}/${file.path}`))
|
|
2775
|
+
: [];
|
|
2776
|
+
}),
|
|
2777
|
+
...job.traceIds.flatMap((traceId) => {
|
|
2778
|
+
const trace = traceById.get(traceId);
|
|
2779
|
+
return trace
|
|
2780
|
+
? trace.files.filter(isUserFacingEvidenceFile).map((file) => evidenceFileWithPath(file, `cases/${evidencePathSegment(job.caseId)}/jobs/${evidencePathSegment(job.id)}/traces/${evidencePathSegment(trace.id)}/${file.path}`))
|
|
2625
2781
|
: [];
|
|
2626
2782
|
}),
|
|
2627
2783
|
]);
|
|
@@ -2640,6 +2796,10 @@ function evidenceFileWithPath(file, filePath) {
|
|
|
2640
2796
|
path: filePath.replace(/\\/gu, "/").replace(/^\/+/u, ""),
|
|
2641
2797
|
};
|
|
2642
2798
|
}
|
|
2799
|
+
function isUserFacingEvidenceFile(file) {
|
|
2800
|
+
const normalized = file.path.replace(/\\/gu, "/").replace(/^\/+/u, "");
|
|
2801
|
+
return normalized.split("/").every((segment) => segment !== ".workbench");
|
|
2802
|
+
}
|
|
2643
2803
|
function evidencePathSegment(value) {
|
|
2644
2804
|
return value.replace(/[^A-Za-z0-9._-]+/gu, "-") || "_";
|
|
2645
2805
|
}
|
|
@@ -2648,6 +2808,24 @@ function formatRunOrJobEvidence(details, files) {
|
|
|
2648
2808
|
const fileLines = files.length > 0 ? ["Files:", ...files.map((file) => file.path)] : [];
|
|
2649
2809
|
return [...detailLines, ...fileLines].join("\n") || "No evidence.";
|
|
2650
2810
|
}
|
|
2811
|
+
function evidenceDetailSummary(detail) {
|
|
2812
|
+
return {
|
|
2813
|
+
runId: detail.runId,
|
|
2814
|
+
executions: detail.executions.map((execution) => ({
|
|
2815
|
+
id: execution.id,
|
|
2816
|
+
status: execution.status,
|
|
2817
|
+
jobIds: execution.jobIds,
|
|
2818
|
+
sessions: execution.sessions.map((session) => ({
|
|
2819
|
+
label: session.label,
|
|
2820
|
+
})),
|
|
2821
|
+
trace: {
|
|
2822
|
+
events: execution.trace.events.length,
|
|
2823
|
+
spans: execution.trace.spans.length,
|
|
2824
|
+
summaries: execution.trace.summaries.length,
|
|
2825
|
+
},
|
|
2826
|
+
})),
|
|
2827
|
+
};
|
|
2828
|
+
}
|
|
2651
2829
|
function manifestOnly(value) {
|
|
2652
2830
|
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
2653
2831
|
return value;
|
|
@@ -2770,6 +2948,17 @@ function findShowFile(files, requestedPath, objectRef) {
|
|
|
2770
2948
|
const candidates = normalized === "stderr.log"
|
|
2771
2949
|
? suffixCandidates.filter((file) => file.content.length > 0)
|
|
2772
2950
|
: suffixCandidates;
|
|
2951
|
+
const canonicalCandidates = candidates.filter(isCanonicalEvidenceFileCandidate);
|
|
2952
|
+
if (canonicalCandidates.length === 1) {
|
|
2953
|
+
return canonicalCandidates[0];
|
|
2954
|
+
}
|
|
2955
|
+
const equivalentCanonicalCandidate = singleEquivalentShowFile(canonicalCandidates);
|
|
2956
|
+
if (equivalentCanonicalCandidate) {
|
|
2957
|
+
return equivalentCanonicalCandidate;
|
|
2958
|
+
}
|
|
2959
|
+
if (canonicalCandidates.length > 1) {
|
|
2960
|
+
throw ambiguousShowPath(objectRef, requestedPath, canonicalCandidates);
|
|
2961
|
+
}
|
|
2773
2962
|
if (candidates.length === 1) {
|
|
2774
2963
|
return candidates[0];
|
|
2775
2964
|
}
|
|
@@ -2786,6 +2975,9 @@ function findShowFile(files, requestedPath, objectRef) {
|
|
|
2786
2975
|
}
|
|
2787
2976
|
throw ambiguousShowPath(objectRef, requestedPath, candidates.length > 0 ? candidates : suffixCandidates);
|
|
2788
2977
|
}
|
|
2978
|
+
function isCanonicalEvidenceFileCandidate(file) {
|
|
2979
|
+
return !file.path.includes("/traces/") && !file.path.includes("/artifacts/");
|
|
2980
|
+
}
|
|
2789
2981
|
function singleEquivalentShowFile(files) {
|
|
2790
2982
|
if (files.length <= 1) {
|
|
2791
2983
|
return null;
|
|
@@ -2831,24 +3023,56 @@ async function traceIdForCaseSource(core, ref) {
|
|
|
2831
3023
|
exitCode: 1,
|
|
2832
3024
|
});
|
|
2833
3025
|
}
|
|
3026
|
+
async function evalCoverageSummaries(core, runs) {
|
|
3027
|
+
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(core);
|
|
3028
|
+
const jobsByRun = new Map();
|
|
3029
|
+
for (const job of snapshot.jobs) {
|
|
3030
|
+
const existing = jobsByRun.get(job.runId) ?? [];
|
|
3031
|
+
existing.push(job);
|
|
3032
|
+
jobsByRun.set(job.runId, existing);
|
|
3033
|
+
}
|
|
3034
|
+
return runs.map((run) => {
|
|
3035
|
+
const jobs = jobsByRun.get(run.id) ?? [];
|
|
3036
|
+
const cases = new Set(jobs.map((job) => job.caseId));
|
|
3037
|
+
const samples = new Set(jobs.map((job) => `${job.caseId}\0${job.sample}`));
|
|
3038
|
+
return {
|
|
3039
|
+
runId: run.id,
|
|
3040
|
+
cases: cases.size,
|
|
3041
|
+
samples: samples.size,
|
|
3042
|
+
jobs: jobs.length,
|
|
3043
|
+
succeeded: jobs.filter((job) => job.status === "succeeded").length,
|
|
3044
|
+
failed: jobs.filter((job) => job.status === "failed" || job.status === "canceled").length,
|
|
3045
|
+
};
|
|
3046
|
+
});
|
|
3047
|
+
}
|
|
3048
|
+
function formatEvalCoverage(coverage) {
|
|
3049
|
+
return [
|
|
3050
|
+
`coverage cases=${coverage.cases}`,
|
|
3051
|
+
`samples=${coverage.samples}`,
|
|
3052
|
+
`jobs=${coverage.jobs}`,
|
|
3053
|
+
coverage.failed > 0 ? `failed=${coverage.failed}` : undefined,
|
|
3054
|
+
].filter(Boolean).join(" ");
|
|
3055
|
+
}
|
|
2834
3056
|
async function evalDeltas(core, runs) {
|
|
2835
3057
|
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(core);
|
|
2836
3058
|
return runs.map((run) => {
|
|
3059
|
+
const score = scoredRunValue(run);
|
|
2837
3060
|
const previous = snapshot.runs
|
|
2838
3061
|
.filter((candidate) => candidate.id !== run.id &&
|
|
2839
3062
|
candidate.skillName === run.skillName &&
|
|
2840
3063
|
candidate.agentName === run.agentName &&
|
|
2841
|
-
|
|
3064
|
+
scoredRunValue(candidate) !== undefined &&
|
|
2842
3065
|
candidate.createdAt < run.createdAt)
|
|
2843
3066
|
.sort((left, right) => right.createdAt.localeCompare(left.createdAt))[0];
|
|
3067
|
+
const previousScore = previous ? scoredRunValue(previous) : undefined;
|
|
2844
3068
|
return {
|
|
2845
3069
|
runId: run.id,
|
|
2846
3070
|
versionId: run.versionId,
|
|
2847
3071
|
skillName: run.skillName,
|
|
2848
3072
|
agentName: run.agentName,
|
|
2849
|
-
...(
|
|
2850
|
-
...(
|
|
2851
|
-
...(
|
|
3073
|
+
...(score !== undefined ? { score } : {}),
|
|
3074
|
+
...(previousScore !== undefined ? { previousScore } : {}),
|
|
3075
|
+
...(score !== undefined && previousScore !== undefined ? { delta: score - previousScore } : {}),
|
|
2852
3076
|
};
|
|
2853
3077
|
});
|
|
2854
3078
|
}
|
|
@@ -2867,15 +3091,11 @@ async function evalSuccessNextCommand(core, runs) {
|
|
|
2867
3091
|
if (runs.length === 0) {
|
|
2868
3092
|
return "workbench eval";
|
|
2869
3093
|
}
|
|
2870
|
-
if (!runs.some((run) =>
|
|
3094
|
+
if (!runs.some((run) => scoredRunValue(run) !== undefined)) {
|
|
2871
3095
|
return "edit .workbench/cases, then run workbench eval";
|
|
2872
3096
|
}
|
|
2873
3097
|
const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(core);
|
|
2874
|
-
|
|
2875
|
-
const caseFiles = currentVersion?.files.filter((file) => file.kind === "text" &&
|
|
2876
|
-
/^\.workbench\/cases\/[^/]+\/case\.ya?ml$/u.test(file.path)) ?? [];
|
|
2877
|
-
const hasWorkflowCase = caseFiles.some((file) => file.kind === "text" && !/\n\s*smoke:\s*true(?:\s|$)/u.test(`\n${file.content}`));
|
|
2878
|
-
return hasWorkflowCase ? "workbench publish" : "edit .workbench/cases, then run workbench eval";
|
|
3098
|
+
return snapshotHasWorkflowCase(snapshot) ? "workbench publish" : "edit .workbench/cases, then run workbench eval";
|
|
2879
3099
|
}
|
|
2880
3100
|
function formatStatusSnapshot(status) {
|
|
2881
3101
|
const lines = [
|
|
@@ -2927,7 +3147,8 @@ function formatAgent(agent) {
|
|
|
2927
3147
|
return `${agent.name}\t${agent.adapter}${agent.model ? `\t${agent.model}` : ""}`;
|
|
2928
3148
|
}
|
|
2929
3149
|
function formatRun(run) {
|
|
2930
|
-
const
|
|
3150
|
+
const scoreValue = scoredRunValue(run);
|
|
3151
|
+
const score = scoreValue === undefined ? "n/a" : scoreValue.toFixed(3);
|
|
2931
3152
|
const latency = run.latencyMs === undefined ? "n/a" : `${run.latencyMs}ms`;
|
|
2932
3153
|
return `${displayRef(run.id)}\t${run.kind}\t${run.status}\tversion=${displayRef(run.versionId)}\tskill=${run.skillName}\tagent=${run.agentName}\tscore=${score}\tlatency=${latency}`;
|
|
2933
3154
|
}
|
|
@@ -2940,7 +3161,8 @@ function formatImproveResult(result) {
|
|
|
2940
3161
|
].join("\n");
|
|
2941
3162
|
}
|
|
2942
3163
|
function formatJob(job) {
|
|
2943
|
-
const
|
|
3164
|
+
const scoreValue = scoredJobValue(job);
|
|
3165
|
+
const score = scoreValue === undefined ? "n/a" : scoreValue.toFixed(3);
|
|
2944
3166
|
const duration = job.durationMs === undefined ? "n/a" : `${job.durationMs}ms`;
|
|
2945
3167
|
return `${displayRef(job.id)}\trun=${displayRef(job.runId)}\tcase=${job.caseId}\tsample=${job.sample}\t${job.status}\tscore=${score}\tduration=${duration}`;
|
|
2946
3168
|
}
|
|
@@ -2966,7 +3188,7 @@ function shortObjectId(id) {
|
|
|
2966
3188
|
function formatTrace(trace) {
|
|
2967
3189
|
const result = asRecord(trace.result);
|
|
2968
3190
|
const status = typeof result?.status === "string" ? result.status : undefined;
|
|
2969
|
-
const score = typeof result?.score === "number" ? result.score.toFixed(3) : undefined;
|
|
3191
|
+
const score = status === "succeeded" && typeof result?.score === "number" ? result.score.toFixed(3) : undefined;
|
|
2970
3192
|
const error = typeof result?.error === "string" ? result.error.split(/\r?\n/u)[0] : undefined;
|
|
2971
3193
|
const files = trace.files.slice(0, 5).map((file) => file.path).join(",");
|
|
2972
3194
|
return [
|
|
@@ -2979,6 +3201,7 @@ function formatTrace(trace) {
|
|
|
2979
3201
|
}
|
|
2980
3202
|
function traceSummary(trace) {
|
|
2981
3203
|
const result = asRecord(trace.result);
|
|
3204
|
+
const status = typeof result?.status === "string" ? result.status : undefined;
|
|
2982
3205
|
return {
|
|
2983
3206
|
id: trace.id,
|
|
2984
3207
|
runId: trace.runId,
|
|
@@ -2987,8 +3210,8 @@ function traceSummary(trace) {
|
|
|
2987
3210
|
skillName: trace.skillName,
|
|
2988
3211
|
agentName: trace.agentName,
|
|
2989
3212
|
createdAt: trace.createdAt,
|
|
2990
|
-
...(
|
|
2991
|
-
...(typeof result?.score === "number" ? { score: result.score } : {}),
|
|
3213
|
+
...(status ? { status } : {}),
|
|
3214
|
+
...(status === "succeeded" && typeof result?.score === "number" ? { score: result.score } : {}),
|
|
2992
3215
|
...(typeof result?.error === "string" ? { error: singleLine(result.error) } : {}),
|
|
2993
3216
|
fileCount: trace.files.length,
|
|
2994
3217
|
files: trace.files.map(fileSummary),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-ai/workbench",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.73",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/workbench-ai/workbench.git",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"yaml": "^2.8.2",
|
|
24
|
-
"@workbench-ai/workbench-built-in-adapters": "0.0.
|
|
25
|
-
"@workbench-ai/workbench-
|
|
26
|
-
"@workbench-ai/workbench-contract": "0.0.
|
|
27
|
-
"@workbench-ai/workbench-
|
|
24
|
+
"@workbench-ai/workbench-built-in-adapters": "0.0.73",
|
|
25
|
+
"@workbench-ai/workbench-protocol": "0.0.73",
|
|
26
|
+
"@workbench-ai/workbench-contract": "0.0.73",
|
|
27
|
+
"@workbench-ai/workbench-core": "0.0.73"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@tailwindcss/postcss": "^4.2.2",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"react-dom": "^19.2.0",
|
|
36
36
|
"typescript": "^5.9.2",
|
|
37
37
|
"vitest": "^3.2.4",
|
|
38
|
-
"@workbench-ai/workbench-ui": "0.0.
|
|
38
|
+
"@workbench-ai/workbench-ui": "0.0.73"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "rm -rf dist && tsc -p tsconfig.json && chmod 755 dist/workbench.js && node ./scripts/build-dev-open-assets.mjs",
|