@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.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -53
- package/package.json +6 -7
- package/dist/fanout.d.ts +0 -13
- package/dist/fanout.d.ts.map +0 -1
- package/dist/fanout.js +0 -223
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,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
|
-
|
|
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.
|
|
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.
|
|
26
|
-
"@workbench-ai/workbench-contract": "0.0.
|
|
27
|
-
"@workbench-ai/workbench-
|
|
28
|
-
"@workbench-ai/workbench-
|
|
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.
|
|
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
|
package/dist/fanout.d.ts.map
DELETED
|
@@ -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
|
-
}
|