@workbench-ai/workbench 0.0.86 → 0.0.87

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkEA,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,CAqMlB"}
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,CAqMlB"}
package/dist/index.js CHANGED
@@ -7,7 +7,6 @@ import { gzipSync } from "node:zlib";
7
7
  import { addWorkbenchRemote, addWorkbenchAgent, compareWorkbench, createWorkbenchVersionRuntimeSnapshot, 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
- import { fanOutSkill, manualFanOutCommand } from "./fanout.js";
11
10
  import { installedInventoryToJson, installSnapshotToStore, normalizeInstallSnapshotPath, readInstalledSkillsInventory, } from "./install-targets.js";
12
11
  import { startWorkbenchOpenServer } from "./open-server.js";
13
12
  const require = createRequire(import.meta.url);
@@ -907,10 +906,6 @@ async function handleInstall(parsed, io) {
907
906
  baseUrl: workbenchSource.baseUrl,
908
907
  },
909
908
  });
910
- const fanout = parsed.flags["dry-run"] === true
911
- ? skippedFanOut(result.directoryName, result.destination, result.result === "unchanged" ? "unchanged" : "dry-run")
912
- : await fanOutSkill(result.directoryName, { skillDir: result.destination });
913
- const next = installNextCommand(fanout);
914
909
  return emitResult("workbench.cli.install.v1", {
915
910
  source: sourceSummary,
916
911
  result: result.result,
@@ -921,14 +916,9 @@ async function handleInstall(parsed, io) {
921
916
  filesCopied: result.filesCopied,
922
917
  contentHash: result.contentHash,
923
918
  provenancePath: result.provenancePath,
924
- fanout: fanOutToJson(fanout),
925
- next: next,
919
+ next: null,
926
920
  ...(parsed.flags["dry-run"] === true ? { dryRun: true } : {}),
927
- }, parsed, io, () => [
928
- formatInstallOutcome(result, parsed.flags["dry-run"] === true),
929
- formatFanOut(fanout),
930
- ...(next ? [`next: ${next}`] : []),
931
- ].join("\n"));
921
+ }, parsed, io, () => formatInstallOutcome(result, parsed.flags["dry-run"] === true));
932
922
  }
933
923
  async function handleCloudEval(parsed, io) {
934
924
  const started = await startCloudExecution("eval", parsed, io);
@@ -1008,19 +998,6 @@ async function handleCloudImprove(parsed, io) {
1008
998
  ...(next ? [`next: ${next}`] : []),
1009
999
  ].filter(Boolean).join("\n"));
1010
1000
  }
1011
- function skippedFanOut(name, destination, reason) {
1012
- return {
1013
- status: "skipped",
1014
- command: manualFanOutCommand(destination, name),
1015
- linkedAgents: [],
1016
- reason,
1017
- };
1018
- }
1019
- function installNextCommand(fanout) {
1020
- return fanout.status === "failed" || (fanout.status === "skipped" && fanout.reason !== "dry-run" && fanout.reason !== "unchanged")
1021
- ? fanout.command
1022
- : null;
1023
- }
1024
1001
  function formatInstallOutcome(result, dryRun) {
1025
1002
  if (dryRun) {
1026
1003
  if (result.result === "unchanged") {
@@ -1048,34 +1025,6 @@ function formatInstallOutcome(result, dryRun) {
1048
1025
  function formatFileCount(count) {
1049
1026
  return `${count} ${count === 1 ? "file" : "files"}`;
1050
1027
  }
1051
- function fanOutToJson(fanout) {
1052
- return {
1053
- status: fanout.status,
1054
- command: fanout.command,
1055
- linkedAgents: fanout.linkedAgents,
1056
- ...(fanout.additionalAgents ? { additionalAgents: fanout.additionalAgents } : {}),
1057
- ...(fanout.reason ? { reason: fanout.reason } : {}),
1058
- ...(fanout.exitCode !== undefined ? { exitCode: fanout.exitCode } : {}),
1059
- };
1060
- }
1061
- function formatFanOut(fanout) {
1062
- if (fanout.status === "skipped") {
1063
- if (fanout.reason === "dry-run") {
1064
- return "fanout: planned";
1065
- }
1066
- if (fanout.reason === "unchanged") {
1067
- return "fanout: unchanged";
1068
- }
1069
- return `fanout skipped: ${fanout.reason ?? "not available"}`;
1070
- }
1071
- if (fanout.status === "failed") {
1072
- return `fanout failed: ${fanout.reason ?? "unknown failure"}`;
1073
- }
1074
- if (fanout.linkedAgents.length === 0) {
1075
- return "fanout: completed";
1076
- }
1077
- return "fanout: completed";
1078
- }
1079
1028
  async function latestInstallVersion(record) {
1080
1029
  const handle = normalizedOwnerSkillHandle(record.handle);
1081
1030
  if (!handle) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workbench-ai/workbench",
3
- "version": "0.0.86",
3
+ "version": "0.0.87",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/workbench-ai/workbench.git",
@@ -20,12 +20,11 @@
20
20
  "dist"
21
21
  ],
22
22
  "dependencies": {
23
- "skills": "1.5.11",
24
23
  "yaml": "^2.8.2",
25
- "@workbench-ai/workbench-built-in-adapters": "0.0.86",
26
- "@workbench-ai/workbench-contract": "0.0.86",
27
- "@workbench-ai/workbench-core": "0.0.86",
28
- "@workbench-ai/workbench-protocol": "0.0.86"
24
+ "@workbench-ai/workbench-built-in-adapters": "0.0.87",
25
+ "@workbench-ai/workbench-contract": "0.0.87",
26
+ "@workbench-ai/workbench-protocol": "0.0.87",
27
+ "@workbench-ai/workbench-core": "0.0.87"
29
28
  },
30
29
  "devDependencies": {
31
30
  "@tailwindcss/postcss": "^4.2.2",
@@ -36,7 +35,7 @@
36
35
  "react-dom": "^19.2.0",
37
36
  "typescript": "^5.9.2",
38
37
  "vitest": "^3.2.4",
39
- "@workbench-ai/workbench-ui": "0.0.86"
38
+ "@workbench-ai/workbench-ui": "0.0.87"
40
39
  },
41
40
  "scripts": {
42
41
  "build": "rm -rf dist && tsc -p tsconfig.json && chmod 755 dist/workbench.js && node ./scripts/build-dev-open-assets.mjs",
package/dist/fanout.d.ts DELETED
@@ -1,13 +0,0 @@
1
- export interface FanOutResult {
2
- status: "completed" | "skipped" | "failed";
3
- command: string;
4
- linkedAgents: string[];
5
- additionalAgents?: number;
6
- reason?: string;
7
- exitCode?: number | null;
8
- }
9
- export declare function fanOutSkill(name: string, options: {
10
- skillDir: string;
11
- }): Promise<FanOutResult>;
12
- export declare function manualFanOutCommand(skillDir: string, name: string): string;
13
- //# sourceMappingURL=fanout.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fanout.d.ts","sourceRoot":"","sources":["../src/fanout.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAoEpG;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAO1E"}
package/dist/fanout.js DELETED
@@ -1,223 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { promises as fs } from "node:fs";
3
- import { createRequire } from "node:module";
4
- import os from "node:os";
5
- import path from "node:path";
6
- const require = createRequire(import.meta.url);
7
- const FANOUT_TIMEOUT_MS = 30_000;
8
- export async function fanOutSkill(name, options) {
9
- const resolved = await resolveSkillsBin().catch((error) => ({
10
- binPath: null,
11
- reason: error instanceof Error ? error.message : "Unable to resolve skills package.",
12
- }));
13
- const command = manualFanOutCommand(options.skillDir, name);
14
- if (!resolved.binPath) {
15
- return {
16
- status: "skipped",
17
- command,
18
- linkedAgents: [],
19
- reason: resolved.reason,
20
- };
21
- }
22
- const stagingRoot = await fs.mkdtemp(path.join(os.tmpdir(), "workbench-skills-fanout-"));
23
- const stagedSkillDir = path.join(stagingRoot, name);
24
- try {
25
- await fs.cp(options.skillDir, stagedSkillDir, {
26
- recursive: true,
27
- force: true,
28
- dereference: true,
29
- });
30
- const args = [
31
- resolved.binPath,
32
- "add",
33
- stagedSkillDir,
34
- "--global",
35
- "--yes",
36
- ];
37
- const child = await runNode(args, minimalChildEnv(process.env), FANOUT_TIMEOUT_MS);
38
- const { linkedAgents, additionalAgents } = parseFanOutAgents(`${child.stdout}\n${child.stderr}`);
39
- if (child.timedOut) {
40
- return {
41
- status: "failed",
42
- command,
43
- linkedAgents,
44
- ...(additionalAgents > 0 ? { additionalAgents } : {}),
45
- reason: `skills fan-out timed out after ${FANOUT_TIMEOUT_MS}ms.`,
46
- exitCode: child.exitCode,
47
- };
48
- }
49
- if (child.exitCode !== 0) {
50
- return {
51
- status: "failed",
52
- command,
53
- linkedAgents,
54
- ...(additionalAgents > 0 ? { additionalAgents } : {}),
55
- reason: conciseFailureReason(`${child.stdout}\n${child.stderr}`) ?? `skills fan-out exited ${child.exitCode}.`,
56
- exitCode: child.exitCode,
57
- };
58
- }
59
- return {
60
- status: "completed",
61
- command,
62
- linkedAgents,
63
- ...(additionalAgents > 0 ? { additionalAgents } : {}),
64
- exitCode: child.exitCode,
65
- };
66
- }
67
- catch (error) {
68
- return {
69
- status: "failed",
70
- command,
71
- linkedAgents: [],
72
- reason: error instanceof Error ? error.message : "skills fan-out failed.",
73
- };
74
- }
75
- finally {
76
- await fs.rm(stagingRoot, { recursive: true, force: true });
77
- }
78
- }
79
- export function manualFanOutCommand(skillDir, name) {
80
- const quotedName = quoteShellArg(name);
81
- return [
82
- "tmpdir=$(mktemp -d)",
83
- `cp -R ${quoteShellArg(skillDir)} "$tmpdir"/${quotedName}`,
84
- `skills add "$tmpdir"/${quotedName} --global --yes`,
85
- ].join(" && ");
86
- }
87
- function quoteShellArg(value) {
88
- return /^[A-Za-z0-9_./:=@+-]+$/u.test(value)
89
- ? value
90
- : `'${value.replace(/'/gu, "'\\''")}'`;
91
- }
92
- async function resolveSkillsBin() {
93
- const packageJsonPath = require.resolve("skills/package.json");
94
- const packageRoot = path.dirname(packageJsonPath);
95
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
96
- const bin = typeof packageJson.bin === "string" ? packageJson.bin : packageJson.bin?.skills;
97
- if (!bin) {
98
- throw new Error("The skills package does not declare a skills bin.");
99
- }
100
- return {
101
- binPath: path.resolve(packageRoot, bin),
102
- };
103
- }
104
- function runNode(args, env, timeoutMs) {
105
- return new Promise((resolve) => {
106
- const child = spawn(process.execPath, args, {
107
- env,
108
- stdio: ["ignore", "pipe", "pipe"],
109
- windowsHide: true,
110
- });
111
- let stdout = "";
112
- let stderr = "";
113
- let timedOut = false;
114
- const timer = setTimeout(() => {
115
- timedOut = true;
116
- child.kill("SIGTERM");
117
- }, timeoutMs);
118
- child.stdout?.setEncoding("utf8");
119
- child.stderr?.setEncoding("utf8");
120
- child.stdout?.on("data", (chunk) => {
121
- stdout += chunk;
122
- });
123
- child.stderr?.on("data", (chunk) => {
124
- stderr += chunk;
125
- });
126
- child.on("error", (error) => {
127
- clearTimeout(timer);
128
- resolve({
129
- exitCode: 1,
130
- stdout,
131
- stderr: stderr || error.message,
132
- timedOut,
133
- });
134
- });
135
- child.on("close", (exitCode) => {
136
- clearTimeout(timer);
137
- resolve({
138
- exitCode,
139
- stdout,
140
- stderr,
141
- timedOut,
142
- });
143
- });
144
- });
145
- }
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
- }
180
- }
181
- return next;
182
- }
183
- function parseFanOutAgents(output) {
184
- const cleaned = stripAnsi(output);
185
- const linked = new Set();
186
- let additionalAgents = 0;
187
- for (const line of cleaned.split(/\r?\n/u)) {
188
- const normalized = line.replace(/[\u2502\u25c7\u25cf\u25a0\u2713\u2717]/gu, " ").trim();
189
- const match = /^(?:universal|symlinked|copied|copy\s*\u2192|symlink\s*\u2192):\s*(.+)$/u.exec(normalized);
190
- if (!match) {
191
- continue;
192
- }
193
- for (const rawAgent of match[1].split(",").map((entry) => entry.trim())) {
194
- const moreMatch = /\+(\d+) more$/u.exec(rawAgent);
195
- if (moreMatch) {
196
- additionalAgents += Number(moreMatch[1]);
197
- }
198
- const agent = rawAgent.replace(/\s*\+\d+ more$/u, "").trim();
199
- if (agent) {
200
- linked.add(agent);
201
- }
202
- }
203
- }
204
- return {
205
- linkedAgents: [...linked].sort((left, right) => left.localeCompare(right)),
206
- additionalAgents,
207
- };
208
- }
209
- function conciseFailureReason(output) {
210
- const lines = stripAnsi(output)
211
- .split(/\r?\n/u)
212
- .map((line) => line.replace(/[\u2500-\u257f\u25a0\u25cf\u25c7\u2713\u2717]/gu, " ").trim())
213
- .filter((line) => line.length > 0 &&
214
- !/^skills\s*$/iu.test(line) &&
215
- !/^Tip:/u.test(line) &&
216
- !/^(Source|Local path|Found \d+ skill|Available skills|Installed \d+ skill|Done!|Review skills)/u.test(line) &&
217
- !/^- /u.test(line));
218
- const reason = lines.at(-1);
219
- return reason ? (reason.length > 200 ? `${reason.slice(0, 197)}...` : reason) : null;
220
- }
221
- function stripAnsi(value) {
222
- return value.replace(/\x1B\[[0-?]*[ -/]*[@-~]/gu, "");
223
- }