@workbench-ai/workbench 0.0.74 → 0.0.75

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/fanout.js CHANGED
@@ -34,7 +34,7 @@ export async function fanOutSkill(name, options) {
34
34
  "--global",
35
35
  "--yes",
36
36
  ];
37
- const child = await runNode(args, scrubAgentRuntimeEnv(process.env), FANOUT_TIMEOUT_MS);
37
+ const child = await runNode(args, minimalChildEnv(process.env), FANOUT_TIMEOUT_MS);
38
38
  const { linkedAgents, additionalAgents } = parseFanOutAgents(`${child.stdout}\n${child.stderr}`);
39
39
  if (child.timedOut) {
40
40
  return {
@@ -143,29 +143,40 @@ function runNode(args, env, timeoutMs) {
143
143
  });
144
144
  });
145
145
  }
146
- function scrubAgentRuntimeEnv(env) {
147
- const next = { ...env };
148
- for (const key of [
149
- "AI_AGENT",
150
- "CODEX_SANDBOX",
151
- "CODEX_CI",
152
- "CODEX_THREAD_ID",
153
- "CURSOR_TRACE_ID",
154
- "CURSOR_AGENT",
155
- "CURSOR_EXTENSION_HOST_ROLE",
156
- "GEMINI_CLI",
157
- "ANTIGRAVITY_AGENT",
158
- "AUGMENT_AGENT",
159
- "OPENCODE_CLIENT",
160
- "CLAUDECODE",
161
- "CLAUDE_CODE",
162
- "CLAUDE_CODE_IS_COWORK",
163
- "REPL_ID",
164
- "COPILOT_MODEL",
165
- "COPILOT_ALLOW_ALL",
166
- "COPILOT_GITHUB_TOKEN",
167
- ]) {
168
- delete next[key];
146
+ // The skills CLI changes behavior when it detects it is running inside an
147
+ // agent (via @vercel/detect-agent reading agent-specific environment
148
+ // variables). Fan-out must always run in machine mode, so the child gets a
149
+ // minimal allowlisted environment instead of a hand-maintained blacklist of
150
+ // every agent's marker variables.
151
+ function minimalChildEnv(env) {
152
+ const allowed = [
153
+ "PATH",
154
+ "HOME",
155
+ "USER",
156
+ "SHELL",
157
+ "TMPDIR",
158
+ "TMP",
159
+ "TEMP",
160
+ "LANG",
161
+ "NODE_EXTRA_CA_CERTS",
162
+ "HTTP_PROXY",
163
+ "HTTPS_PROXY",
164
+ "NO_PROXY",
165
+ "http_proxy",
166
+ "https_proxy",
167
+ "no_proxy",
168
+ "SYSTEMROOT",
169
+ "SystemRoot",
170
+ "COMSPEC",
171
+ "APPDATA",
172
+ "LOCALAPPDATA",
173
+ "USERPROFILE",
174
+ ];
175
+ const next = {};
176
+ for (const key of Object.keys(env)) {
177
+ if (allowed.includes(key) || key.startsWith("XDG_") || key.startsWith("LC_")) {
178
+ next[key] = env[key];
179
+ }
169
180
  }
170
181
  return next;
171
182
  }
@@ -1 +1 @@
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,CAsMlB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgEA,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
@@ -4,7 +4,7 @@ import { createRequire } from "node:module";
4
4
  import os from "node:os";
5
5
  import path from "node:path";
6
6
  import { gzipSync } from "node:zlib";
7
- import { addWorkbenchRemote, addWorkbenchAgent, compareWorkbench, createWorkbenchInspectionSnapshot, createWorkbenchAdapterAuthBundle, createWorkbenchReadOnlyInspectionSnapshot, diffWorkbenchVersions, evalWorkbenchSkill, improveWorkbenchSkill, initWorkbenchSkill, listWorkbenchAgents, listWorkbenchVersions, localWorkbenchAdapterAuthStore, parseWorkbenchAdapterAuthTarget, prepareWorkbenchCloudEvalRequest, prepareWorkbenchCloudImproveRequest, publishWorkbenchVersion, removeWorkbenchAgent, showWorkbenchRef, switchWorkbenchVersion, syncWorkbenchRemote, workbenchJobEvidenceForSnapshot, workbenchSkillImproveCanUseQueuedAdapter, workbenchStatusSnapshot, WorkbenchCodedError, WorkbenchUserError, } from "@workbench-ai/workbench-core";
7
+ import { addWorkbenchRemote, addWorkbenchAgent, compareWorkbench, createWorkbenchInspectionSnapshot, createWorkbenchAdapterAuthBundle, createWorkbenchReadOnlyInspectionSnapshot, diffWorkbenchVersions, evalWorkbenchSkill, improveWorkbenchSkill, initWorkbenchSkill, listWorkbenchAgents, listWorkbenchVersions, localWorkbenchAdapterAuthStore, parseWorkbenchAdapterAuthTarget, prepareWorkbenchCloudEvalRequest, prepareWorkbenchCloudImproveRequest, publishWorkbenchVersion, removeWorkbenchAgent, showWorkbenchRef, switchWorkbenchVersion, syncWorkbenchRemote, workbenchJobEvidenceForSnapshot, workbenchStatusSnapshot, WorkbenchCodedError, WorkbenchUserError, } from "@workbench-ai/workbench-core";
8
8
  import { normalizeWorkbenchSkillName } from "@workbench-ai/workbench-contract";
9
9
  import { emitError, emitResult } from "./output.js";
10
10
  import { fanOutSkill, manualFanOutCommand } from "./fanout.js";
@@ -375,12 +375,10 @@ export async function runCli(argv, io = {
375
375
  if (parsed.flags.cloud === true) {
376
376
  return await handleCloudImprove(parsed, io);
377
377
  }
378
- const improverAgent = await resolveLocalImproverAgent(parsed, core);
379
378
  const result = await improveWorkbenchSkill({
380
379
  ...core,
381
380
  skill: stringFlag(parsed, "skills"),
382
381
  agent: stringFlag(parsed, "agents"),
383
- ...(improverAgent ? { improverAgent } : {}),
384
382
  budget: intFlag(parsed, "budget"),
385
383
  samples: intFlag(parsed, "samples"),
386
384
  });
@@ -1110,15 +1108,9 @@ async function startCloudExecution(command, parsed, io) {
1110
1108
  exitCode: 1,
1111
1109
  });
1112
1110
  }
1111
+ const syncAfterSchedule = await syncWorkbenchRemote({ ...core, remote: remote.name });
1113
1112
  const initialRunIds = runs.map((run) => run.id);
1114
1113
  writeCloudProgress(io, `workbench cloud: scheduled hosted ${command} on ${remote.url} (${formatCloudRunStatuses(runs)}).`, showProgress);
1115
- let initialSyncAfter = syncBefore;
1116
- try {
1117
- initialSyncAfter = await syncWorkbenchRemote({ ...core, remote: remote.name });
1118
- }
1119
- catch (error) {
1120
- writeCloudProgress(io, `workbench cloud: sync while waiting failed; retrying (${oneLineExcerpt(errorMessage(error)) ?? "unknown error"}).`, showProgress);
1121
- }
1122
1114
  writeCloudProgress(io, `workbench cloud: waiting for terminal status; press Ctrl-C to detach and resume with workbench show ${displayRef(initialRunIds[0] ?? "run")}.`, showProgress);
1123
1115
  const completed = await waitForCloudRuns({
1124
1116
  command,
@@ -1127,7 +1119,9 @@ async function startCloudExecution(command, parsed, io) {
1127
1119
  progress: showProgress,
1128
1120
  remote,
1129
1121
  runs,
1130
- initialSync: initialSyncAfter,
1122
+ source,
1123
+ skillId,
1124
+ initialSync: syncAfterSchedule,
1131
1125
  });
1132
1126
  return {
1133
1127
  core,
@@ -1163,7 +1157,6 @@ async function waitForCloudRuns(input) {
1163
1157
  let interrupted = false;
1164
1158
  const startedAtMs = Date.now();
1165
1159
  let lastProgressAtMs = startedAtMs;
1166
- let lastSyncErrorMessage;
1167
1160
  const onSigint = () => {
1168
1161
  interrupted = true;
1169
1162
  writeCloudProgress(input.io, `workbench cloud: detaching from hosted ${input.command} (${runIds.map(displayRef).join(", ")}).`, input.progress);
@@ -1172,14 +1165,7 @@ async function waitForCloudRuns(input) {
1172
1165
  const seenStatuses = new Map();
1173
1166
  try {
1174
1167
  while (true) {
1175
- const snapshot = await createWorkbenchReadOnlyInspectionSnapshot(input.core);
1176
- const snapshotRuns = runIds
1177
- .map((id) => snapshot.runs.find((entry) => entry.id === id))
1178
- .filter((run) => Boolean(run));
1179
- if (snapshotRuns.length > 0) {
1180
- runs = runIds.map((id) => snapshotRuns.find((entry) => entry.id === id) ?? runs.find((entry) => entry.id === id))
1181
- .filter((run) => Boolean(run));
1182
- }
1168
+ runs = await fetchCloudRuns(input.source.baseUrl, input.skillId, runIds, runs);
1183
1169
  let wroteProgress = false;
1184
1170
  const nowMs = Date.now();
1185
1171
  for (const run of runs) {
@@ -1191,6 +1177,7 @@ async function waitForCloudRuns(input) {
1191
1177
  }
1192
1178
  }
1193
1179
  if (runs.length === runIds.length && runs.every(isTerminalRun)) {
1180
+ sync = await syncWorkbenchRemote({ ...input.core, remote: input.remote.name });
1194
1181
  return { runs, sync };
1195
1182
  }
1196
1183
  if (wroteProgress) {
@@ -1218,26 +1205,18 @@ async function waitForCloudRuns(input) {
1218
1205
  if (interrupted) {
1219
1206
  return { runs, sync, detached: true };
1220
1207
  }
1221
- try {
1222
- sync = await syncWorkbenchRemote({ ...input.core, remote: input.remote.name });
1223
- if (lastSyncErrorMessage) {
1224
- writeCloudProgress(input.io, "workbench cloud: sync while waiting recovered.", input.progress);
1225
- lastSyncErrorMessage = undefined;
1226
- }
1227
- }
1228
- catch (error) {
1229
- const message = oneLineExcerpt(errorMessage(error)) ?? "unknown error";
1230
- if (message !== lastSyncErrorMessage) {
1231
- writeCloudProgress(input.io, `workbench cloud: sync while waiting failed; retrying (${message}).`, input.progress);
1232
- lastSyncErrorMessage = message;
1233
- }
1234
- }
1235
1208
  }
1236
1209
  }
1237
1210
  finally {
1238
1211
  process.off("SIGINT", onSigint);
1239
1212
  }
1240
1213
  }
1214
+ async function fetchCloudRuns(baseUrl, skillId, runIds, fallback) {
1215
+ const responses = await Promise.all(runIds.map((runId) => apiRequest(`/api/workbench/skills/${encodeURIComponent(skillId)}/runs/${encodeURIComponent(runId)}`, {}, baseUrl)));
1216
+ return runIds
1217
+ .map((runId, index) => responses[index]?.run ?? fallback.find((run) => run.id === runId))
1218
+ .filter((run) => Boolean(run));
1219
+ }
1241
1220
  function isTerminalRun(run) {
1242
1221
  return run.status === "succeeded" || run.status === "failed" || run.status === "canceled";
1243
1222
  }
@@ -1353,15 +1332,11 @@ async function resolveCloudSkillId(source) {
1353
1332
  function cloudExecutionRequestBody(command, request) {
1354
1333
  return {
1355
1334
  versionId: request.versionId,
1356
- evalHash: request.evalHash,
1357
1335
  skill: request.skill,
1358
- skillBundleHash: request.skillBundleHash,
1359
1336
  agent: request.agent,
1360
- agentHash: request.agentHash,
1361
1337
  samples: request.samples,
1362
1338
  ...(command === "improve" ? {
1363
1339
  budget: request.budget,
1364
- evidenceTraceIds: request.evidenceTraceIds,
1365
1340
  } : {}),
1366
1341
  };
1367
1342
  }
@@ -2701,10 +2676,10 @@ async function workbenchMachineStatus(auth) {
2701
2676
  };
2702
2677
  }
2703
2678
  function scoredRunValue(run) {
2704
- return run.status === "succeeded" && typeof run.score === "number" ? run.score : undefined;
2679
+ return typeof run.score === "number" ? run.score : undefined;
2705
2680
  }
2706
2681
  function scoredJobValue(job) {
2707
- return job.status === "succeeded" && typeof job.score === "number" ? job.score : undefined;
2682
+ return typeof job.score === "number" ? job.score : undefined;
2708
2683
  }
2709
2684
  function snapshotHasWorkflowCase(snapshot) {
2710
2685
  const currentVersion = snapshotVersionByRef(snapshot, snapshot.status.currentVersionId ?? snapshot.refs.current ?? "");
@@ -2981,41 +2956,6 @@ function manifestOnly(value) {
2981
2956
  }
2982
2957
  return out;
2983
2958
  }
2984
- async function resolveLocalImproverAgent(parsed, core) {
2985
- if (stringFlag(parsed, "agents")) {
2986
- return undefined;
2987
- }
2988
- const agents = await listWorkbenchAgents(core).catch(() => []);
2989
- const status = await workbenchStatusSnapshot(core).catch(() => undefined);
2990
- const defaultAgentName = status?.project.defaultAgent ?? agents[0]?.name;
2991
- const defaultAgent = agents.find((agent) => agent.name === defaultAgentName);
2992
- if (defaultAgent && workbenchSkillImproveCanUseQueuedAdapter(defaultAgent)) {
2993
- return undefined;
2994
- }
2995
- const connected = await localWorkbenchAdapterAuthStore(adapterAuthStoreRoot()).listStatus().catch(() => []);
2996
- const candidates = connected
2997
- .filter((entry) => entry.status === "connected" &&
2998
- (entry.adapterId === "claude" || entry.adapterId === "codex"))
2999
- .sort((left, right) => {
3000
- const adapterRank = (adapter) => adapter === "claude" ? 0 : adapter === "codex" ? 1 : 2;
3001
- return adapterRank(left.adapterId) - adapterRank(right.adapterId) ||
3002
- (Date.parse(right.updatedAt ?? "") || 0) - (Date.parse(left.updatedAt ?? "") || 0);
3003
- });
3004
- const selected = candidates[0];
3005
- if (!selected) {
3006
- throw new WorkbenchCodedError("auth_required", "workbench improve needs a connected improver.", {
3007
- remediation: "Run workbench login claude (or codex) to connect an improver.",
3008
- exitCode: 1,
3009
- });
3010
- }
3011
- return {
3012
- name: selected.adapterId,
3013
- adapter: selected.adapterId,
3014
- config: {
3015
- auth: selected.slot ? { [selected.slot]: selected.profile } : selected.profile,
3016
- },
3017
- };
3018
- }
3019
2959
  function formatLogEntry(entry) {
3020
2960
  if (entry.kind === "version") {
3021
2961
  return `${entry.createdAt}\tversion\t${displayRef(entry.id)}\tfiles=${entry.fileCount}\t${entry.message}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workbench-ai/workbench",
3
- "version": "0.0.74",
3
+ "version": "0.0.75",
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.74",
26
- "@workbench-ai/workbench-contract": "0.0.74",
27
- "@workbench-ai/workbench-protocol": "0.0.74",
28
- "@workbench-ai/workbench-core": "0.0.74"
25
+ "@workbench-ai/workbench-built-in-adapters": "0.0.75",
26
+ "@workbench-ai/workbench-contract": "0.0.75",
27
+ "@workbench-ai/workbench-core": "0.0.75",
28
+ "@workbench-ai/workbench-protocol": "0.0.75"
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.74"
39
+ "@workbench-ai/workbench-ui": "0.0.75"
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",