@workbench-ai/workbench 0.0.46

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.
Files changed (39) hide show
  1. package/dist/adapter-project.d.ts +29 -0
  2. package/dist/adapter-project.d.ts.map +1 -0
  3. package/dist/adapter-project.js +363 -0
  4. package/dist/benchmark-fingerprint.d.ts +6 -0
  5. package/dist/benchmark-fingerprint.d.ts.map +1 -0
  6. package/dist/benchmark-fingerprint.js +101 -0
  7. package/dist/command-model.d.ts +5 -0
  8. package/dist/command-model.d.ts.map +1 -0
  9. package/dist/command-model.js +558 -0
  10. package/dist/dev-open/client.css +8157 -0
  11. package/dist/dev-open/client.js +252596 -0
  12. package/dist/dev-open/fonts/geist-cyrillic-wght-normal.woff2 +0 -0
  13. package/dist/dev-open/fonts/geist-latin-ext-wght-normal.woff2 +0 -0
  14. package/dist/dev-open/fonts/geist-latin-wght-normal.woff2 +0 -0
  15. package/dist/dev-open-server.d.ts +57 -0
  16. package/dist/dev-open-server.d.ts.map +1 -0
  17. package/dist/dev-open-server.js +496 -0
  18. package/dist/index.d.ts +10 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +3943 -0
  21. package/dist/init-scaffold.d.ts +22 -0
  22. package/dist/init-scaffold.d.ts.map +1 -0
  23. package/dist/init-scaffold.js +30 -0
  24. package/dist/init-template-pack.d.ts +19 -0
  25. package/dist/init-template-pack.d.ts.map +1 -0
  26. package/dist/init-template-pack.js +250 -0
  27. package/dist/local-archive.d.ts +23 -0
  28. package/dist/local-archive.d.ts.map +1 -0
  29. package/dist/local-archive.js +741 -0
  30. package/dist/project-source.d.ts +51 -0
  31. package/dist/project-source.d.ts.map +1 -0
  32. package/dist/project-source.js +700 -0
  33. package/dist/workbench.d.ts +3 -0
  34. package/dist/workbench.d.ts.map +1 -0
  35. package/dist/workbench.js +4 -0
  36. package/dist/workspace-snapshot.d.ts +10 -0
  37. package/dist/workspace-snapshot.d.ts.map +1 -0
  38. package/dist/workspace-snapshot.js +81 -0
  39. package/package.json +45 -0
@@ -0,0 +1,29 @@
1
+ import { type WorkbenchAdapterManifest } from "@workbench-ai/workbench-protocol";
2
+ import { type resolveWorkbenchResolvedSourceYaml } from "@workbench-ai/workbench-core";
3
+ export declare const WORKBENCH_ADAPTER_MANIFEST_FILE = "workbench.adapter.yaml";
4
+ export interface ResolvedWorkbenchAdapter {
5
+ source: string;
6
+ declaredSource: string;
7
+ kind: "default" | "path" | "npm" | "git";
8
+ stability: "default" | "local" | "pinned" | "floating";
9
+ overridesDefault?: boolean;
10
+ manifest: WorkbenchAdapterManifest;
11
+ root?: string;
12
+ files?: WorkbenchAdapterSourceFile[];
13
+ integrity?: string;
14
+ contentHash: string;
15
+ manifestHash: string;
16
+ }
17
+ export interface WorkbenchAdapterSourceFile {
18
+ path: string;
19
+ content: string;
20
+ executable: boolean;
21
+ }
22
+ type GenericSpec = ReturnType<typeof resolveWorkbenchResolvedSourceYaml>;
23
+ export declare function defaultAdapterManifests(): WorkbenchAdapterManifest[];
24
+ export declare function resolveDefaultWorkbenchAdapter(id: string): ResolvedWorkbenchAdapter | null;
25
+ export declare function resolveWorkbenchAdaptersForProject(dir: string, spec: GenericSpec): Promise<ResolvedWorkbenchAdapter[]>;
26
+ export declare function resolveProjectAdapterSource(dir: string, source: string): Promise<ResolvedWorkbenchAdapter>;
27
+ export declare function composeRuntimeDockerfileWithAdapters(dockerfile: string, adapters: readonly ResolvedWorkbenchAdapter[]): Promise<string>;
28
+ export {};
29
+ //# sourceMappingURL=adapter-project.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-project.d.ts","sourceRoot":"","sources":["../src/adapter-project.ts"],"names":[],"mappings":"AAWA,OAAO,EAKL,KAAK,wBAAwB,EAC9B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAEL,KAAK,kCAAkC,EACxC,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,+BAA+B,2BAA2B,CAAC;AAIxE,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IACzC,SAAS,EAAE,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;IACvD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,wBAAwB,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,0BAA0B,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAEzE,wBAAgB,uBAAuB,IAAI,wBAAwB,EAAE,CAEpE;AAED,wBAAgB,8BAA8B,CAAC,EAAE,EAAE,MAAM,GAAG,wBAAwB,GAAG,IAAI,CAG1F;AAED,wBAAsB,kCAAkC,CACtD,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAmDrC;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC,CAwBnC;AAED,wBAAsB,oCAAoC,CACxD,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,SAAS,wBAAwB,EAAE,GAC5C,OAAO,CAAC,MAAM,CAAC,CA2BjB"}
@@ -0,0 +1,363 @@
1
+ import { createHash } from "node:crypto";
2
+ import { execFile } from "node:child_process";
3
+ import { promises as fs } from "node:fs";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { promisify } from "node:util";
7
+ import { builtinWorkbenchAdapterManifest, builtinWorkbenchAdapterManifests, } from "@workbench-ai/workbench-built-in-adapters";
8
+ import { assertWorkbenchAdapterOperationSupport, collectWorkbenchAdapterOperationRequirements, parseWorkbenchAdapterManifest, } from "@workbench-ai/workbench-protocol";
9
+ import { engineResolveInvocationForSpec, } from "@workbench-ai/workbench-core";
10
+ export const WORKBENCH_ADAPTER_MANIFEST_FILE = "workbench.adapter.yaml";
11
+ const execFileAsync = promisify(execFile);
12
+ export function defaultAdapterManifests() {
13
+ return builtinWorkbenchAdapterManifests();
14
+ }
15
+ export function resolveDefaultWorkbenchAdapter(id) {
16
+ const manifest = builtinWorkbenchAdapterManifest(id);
17
+ return manifest ? resolvedDefaultAdapter(manifest) : null;
18
+ }
19
+ export async function resolveWorkbenchAdaptersForProject(dir, spec) {
20
+ const adapters = new Map();
21
+ for (const id of topLevelAdapterIds(spec)) {
22
+ const defaultAdapter = resolveDefaultWorkbenchAdapter(id);
23
+ if (defaultAdapter) {
24
+ adapters.set(id, defaultAdapter);
25
+ }
26
+ }
27
+ for (const source of spec.adapters) {
28
+ const adapter = await resolveProjectAdapterSource(dir, source);
29
+ const existing = adapters.get(adapter.manifest.id);
30
+ const override = adapterOverridesDefault(adapter);
31
+ const resolvedAdapter = {
32
+ ...adapter,
33
+ ...(override ? { overridesDefault: true } : {}),
34
+ };
35
+ if (existing?.kind === "default") {
36
+ adapters.set(adapter.manifest.id, resolvedAdapter);
37
+ continue;
38
+ }
39
+ if (existing && existing.source !== adapter.source) {
40
+ throw new Error(`Adapter id ${adapter.manifest.id} is provided by both ${existing.source} and ${adapter.source}. Remove one adapter source.`);
41
+ }
42
+ adapters.set(adapter.manifest.id, resolvedAdapter);
43
+ }
44
+ let discovered = true;
45
+ while (discovered) {
46
+ discovered = false;
47
+ const manifestById = new Map([...adapters.values()].map((adapter) => [adapter.manifest.id, adapter.manifest]));
48
+ for (const id of requiredAdapterIds(spec, [...manifestById.values()])) {
49
+ if (adapters.has(id)) {
50
+ continue;
51
+ }
52
+ const defaultAdapter = resolveDefaultWorkbenchAdapter(id);
53
+ if (defaultAdapter) {
54
+ adapters.set(id, defaultAdapter);
55
+ discovered = true;
56
+ continue;
57
+ }
58
+ throw new Error(`Adapter ${id} is referenced by benchmark/subject/optimizer YAML but is not installed. List its source under adapters in the YAML file that uses it.`);
59
+ }
60
+ }
61
+ assertWorkbenchAdapterOperationSupport(rootAdapterOperationRequirements(spec), [...adapters.values()].map((adapter) => adapter.manifest));
62
+ return [...adapters.values()].sort((left, right) => left.manifest.id.localeCompare(right.manifest.id));
63
+ }
64
+ export async function resolveProjectAdapterSource(dir, source) {
65
+ if (source.startsWith("npm:")) {
66
+ return await resolveNpmAdapterSource(source);
67
+ }
68
+ if (source.startsWith("git:")) {
69
+ return await resolveGitAdapterSource(source);
70
+ }
71
+ const isPathSource = source.startsWith(".") || source.startsWith("/") || source.includes("/");
72
+ if (!isPathSource) {
73
+ throw new Error(`Adapter source ${source} is not installed locally. Use a benchmark-contained path source, npm: package, or git: URL.`);
74
+ }
75
+ const root = path.resolve(dir, source);
76
+ const relative = path.relative(dir, root);
77
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
78
+ throw new Error(`Adapter source ${source} is outside the benchmark source root. Copy it into the benchmark source tree and list that benchmark-contained path.`);
79
+ }
80
+ return await resolveAdapterFromRoot({
81
+ declaredSource: source,
82
+ source: normalizeSourcePath(relative || "."),
83
+ kind: "path",
84
+ root,
85
+ });
86
+ }
87
+ export async function composeRuntimeDockerfileWithAdapters(dockerfile, adapters) {
88
+ const installAdapters = adapters.filter((adapter) => adapter.manifest.setup.length > 0 || (adapter.files?.length ?? 0) > 0);
89
+ if (installAdapters.length === 0) {
90
+ return dockerfile;
91
+ }
92
+ const lines = [
93
+ dockerfile.trimEnd(),
94
+ "",
95
+ "# Workbench adapter setup. The benchmark Dockerfile owns task dependencies;",
96
+ "# adapter manifests own adapter runtime dependencies.",
97
+ "USER root",
98
+ ];
99
+ for (const adapter of installAdapters) {
100
+ lines.push("");
101
+ lines.push(`# Adapter: ${adapter.manifest.id} (${adapter.source})`);
102
+ if ((adapter.files?.length ?? 0) > 0) {
103
+ lines.push(...adapterSourceDockerfileLines(adapter));
104
+ lines.push(`WORKDIR /opt/workbench-adapters/${adapter.manifest.id}`);
105
+ }
106
+ for (const command of adapter.manifest.setup) {
107
+ lines.push(`RUN ${command}`);
108
+ }
109
+ }
110
+ lines.push("WORKDIR /workspace", "");
111
+ return lines.join("\n");
112
+ }
113
+ function resolvedDefaultAdapter(manifest) {
114
+ const manifestHash = sha256(JSON.stringify(manifest));
115
+ return {
116
+ source: `default:${manifest.id}`,
117
+ declaredSource: `default:${manifest.id}`,
118
+ kind: "default",
119
+ stability: "default",
120
+ manifest: {
121
+ ...manifest,
122
+ operations: JSON.parse(JSON.stringify(manifest.operations)),
123
+ setup: [...manifest.setup],
124
+ ...(manifest.slots ? { slots: JSON.parse(JSON.stringify(manifest.slots)) } : {}),
125
+ },
126
+ manifestHash,
127
+ contentHash: manifestHash,
128
+ };
129
+ }
130
+ function adapterOverridesDefault(adapter) {
131
+ return adapter.kind !== "default" && builtinWorkbenchAdapterManifest(adapter.manifest.id) !== null;
132
+ }
133
+ async function resolveNpmAdapterSource(source) {
134
+ const specifier = source.slice("npm:".length).trim();
135
+ if (!specifier) {
136
+ throw new Error("npm adapter source must include a package specifier.");
137
+ }
138
+ const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "workbench-adapter-npm-"));
139
+ try {
140
+ const npmCache = path.join(tempRoot, "npm-cache");
141
+ const npmLogs = path.join(tempRoot, "npm-logs");
142
+ await fs.mkdir(npmCache, { recursive: true });
143
+ await fs.mkdir(npmLogs, { recursive: true });
144
+ const pack = await execFileUtf8("npm", [
145
+ "pack",
146
+ specifier,
147
+ "--json",
148
+ "--pack-destination",
149
+ tempRoot,
150
+ ], {
151
+ env: {
152
+ ...process.env,
153
+ NPM_CONFIG_CACHE: npmCache,
154
+ NPM_CONFIG_LOGS_DIR: npmLogs,
155
+ },
156
+ });
157
+ const [entry] = JSON.parse(pack.stdout);
158
+ if (!entry?.name || !entry.version || !entry.filename) {
159
+ throw new Error(`npm pack ${specifier} did not return package metadata.`);
160
+ }
161
+ const tarballPath = path.join(tempRoot, entry.filename);
162
+ const extractRoot = path.join(tempRoot, "extract");
163
+ await fs.mkdir(extractRoot, { recursive: true });
164
+ await execFileUtf8("tar", ["-xzf", tarballPath, "-C", extractRoot]);
165
+ return await resolveAdapterFromRoot({
166
+ declaredSource: source,
167
+ source: `npm:${entry.name}@${entry.version}`,
168
+ kind: "npm",
169
+ stability: npmSourceStability(specifier),
170
+ root: path.join(extractRoot, "package"),
171
+ integrity: entry.integrity,
172
+ includeBuildArtifacts: true,
173
+ });
174
+ }
175
+ finally {
176
+ await fs.rm(tempRoot, { recursive: true, force: true }).catch(() => undefined);
177
+ }
178
+ }
179
+ async function resolveGitAdapterSource(source) {
180
+ const specifier = source.slice("git:".length).trim();
181
+ if (!specifier) {
182
+ throw new Error("git adapter source must include a repository URL.");
183
+ }
184
+ const { url, ref } = parseGitSource(specifier);
185
+ const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "workbench-adapter-git-"));
186
+ const checkoutRoot = path.join(tempRoot, "checkout");
187
+ try {
188
+ await cloneGitAdapter(url, ref, checkoutRoot);
189
+ const commit = (await execFileUtf8("git", ["-C", checkoutRoot, "rev-parse", "HEAD"])).stdout.trim();
190
+ return await resolveAdapterFromRoot({
191
+ declaredSource: source,
192
+ source: `git:${url}#${commit}`,
193
+ kind: "git",
194
+ stability: gitSourceStability(ref),
195
+ root: checkoutRoot,
196
+ integrity: commit,
197
+ includeBuildArtifacts: true,
198
+ });
199
+ }
200
+ finally {
201
+ await fs.rm(tempRoot, { recursive: true, force: true }).catch(() => undefined);
202
+ }
203
+ }
204
+ async function resolveAdapterFromRoot(args) {
205
+ const manifestPath = path.join(args.root, WORKBENCH_ADAPTER_MANIFEST_FILE);
206
+ const manifestSource = await fs.readFile(manifestPath, "utf8");
207
+ const manifest = parseWorkbenchAdapterManifest(manifestSource, manifestPath);
208
+ const files = await readAdapterSourceFiles(args.root, {
209
+ includeBuildArtifacts: args.includeBuildArtifacts === true,
210
+ });
211
+ const manifestHash = sha256(manifestSource);
212
+ const contentHash = sha256(JSON.stringify(files.map((file) => ({
213
+ path: file.path,
214
+ executable: file.executable,
215
+ contentHash: sha256(file.content),
216
+ }))));
217
+ return {
218
+ source: args.source,
219
+ declaredSource: args.declaredSource ?? args.source,
220
+ kind: args.kind,
221
+ stability: args.stability ?? "local",
222
+ manifest,
223
+ root: args.root,
224
+ files,
225
+ ...(args.integrity ? { integrity: args.integrity } : {}),
226
+ manifestHash,
227
+ contentHash,
228
+ };
229
+ }
230
+ async function cloneGitAdapter(url, ref, checkoutRoot) {
231
+ if (ref) {
232
+ try {
233
+ await execFileUtf8("git", ["clone", "--depth", "1", "--branch", ref, url, checkoutRoot]);
234
+ return;
235
+ }
236
+ catch {
237
+ await fs.rm(checkoutRoot, { recursive: true, force: true }).catch(() => undefined);
238
+ }
239
+ }
240
+ await execFileUtf8("git", ["clone", "--depth", "1", url, checkoutRoot]);
241
+ if (ref) {
242
+ await execFileUtf8("git", ["-C", checkoutRoot, "fetch", "--depth", "1", "origin", ref]);
243
+ await execFileUtf8("git", ["-C", checkoutRoot, "checkout", "FETCH_HEAD"]);
244
+ }
245
+ }
246
+ function parseGitSource(specifier) {
247
+ const hashIndex = specifier.lastIndexOf("#");
248
+ if (hashIndex < 0) {
249
+ return { url: specifier, ref: null };
250
+ }
251
+ const url = specifier.slice(0, hashIndex);
252
+ const ref = specifier.slice(hashIndex + 1);
253
+ if (!url || !ref) {
254
+ throw new Error(`Invalid git adapter source: git:${specifier}`);
255
+ }
256
+ return { url, ref };
257
+ }
258
+ function npmSourceStability(specifier) {
259
+ return npmSpecifierHasExactVersion(specifier) ? "pinned" : "floating";
260
+ }
261
+ function npmSpecifierHasExactVersion(specifier) {
262
+ const atIndex = specifier.lastIndexOf("@");
263
+ if (atIndex <= 0) {
264
+ return false;
265
+ }
266
+ const version = specifier.slice(atIndex + 1);
267
+ return /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/u.test(version);
268
+ }
269
+ function gitSourceStability(ref) {
270
+ return ref && /^[0-9a-f]{7,40}$/iu.test(ref) ? "pinned" : "floating";
271
+ }
272
+ function topLevelAdapterIds(spec) {
273
+ return [...new Set(rootAdapterInvocations(spec).map((invocation) => invocation.use))];
274
+ }
275
+ function rootAdapterOperationRequirements(spec) {
276
+ return [
277
+ { invocation: engineResolveInvocationForSpec(spec), operation: "engine.resolve" },
278
+ { invocation: spec.engineRun, operation: "engine.run" },
279
+ ...(spec.improve ? [{ invocation: spec.improve, operation: "optimizer.improve" }] : []),
280
+ { invocation: spec.run, operation: "subject.run" },
281
+ ];
282
+ }
283
+ function rootAdapterInvocations(spec) {
284
+ return rootAdapterOperationRequirements(spec).map((requirement) => requirement.invocation);
285
+ }
286
+ function requiredAdapterIds(spec, manifests) {
287
+ const ids = new Set();
288
+ for (const requirement of collectWorkbenchAdapterOperationRequirements(rootAdapterOperationRequirements(spec), manifests)) {
289
+ ids.add(requirement.invocation.use);
290
+ }
291
+ return [...ids];
292
+ }
293
+ function adapterSourceDockerfileLines(adapter) {
294
+ const root = `/opt/workbench-adapters/${adapter.manifest.id}`;
295
+ const lines = [`RUN mkdir -p ${shellWord(root)}`];
296
+ for (const file of adapter.files ?? []) {
297
+ const destination = `${root}/${file.path}`;
298
+ const encoded = Buffer.from(file.content, "utf8").toString("base64");
299
+ lines.push(`RUN mkdir -p ${shellWord(path.posix.dirname(destination))} && printf '%s' ${shellWord(encoded)} | base64 -d > ${shellWord(destination)}${file.executable ? ` && chmod 755 ${shellWord(destination)}` : ""}`);
300
+ }
301
+ return lines;
302
+ }
303
+ async function readAdapterSourceFiles(root, options = {}) {
304
+ const files = [];
305
+ async function visit(relativeDir) {
306
+ const absoluteDir = path.join(root, relativeDir);
307
+ const entries = await fs.readdir(absoluteDir, { withFileTypes: true });
308
+ for (const entry of entries) {
309
+ if (entry.name === "node_modules" ||
310
+ entry.name === ".git" ||
311
+ (!options.includeBuildArtifacts && entry.name === "dist")) {
312
+ continue;
313
+ }
314
+ const relativePath = normalizeSourcePath(path.join(relativeDir, entry.name));
315
+ const absolutePath = path.join(root, relativePath);
316
+ if (entry.isDirectory()) {
317
+ await visit(relativePath);
318
+ continue;
319
+ }
320
+ if (!entry.isFile()) {
321
+ continue;
322
+ }
323
+ const content = await fs.readFile(absolutePath, "utf8");
324
+ const stat = await fs.stat(absolutePath);
325
+ files.push({
326
+ path: relativePath,
327
+ content,
328
+ executable: Boolean(stat.mode & 0o111),
329
+ });
330
+ }
331
+ }
332
+ await visit("");
333
+ return files.sort((left, right) => left.path.localeCompare(right.path));
334
+ }
335
+ function normalizeSourcePath(value) {
336
+ return value.replace(/\\/gu, "/").replace(/^\.?\//u, "");
337
+ }
338
+ function shellWord(value) {
339
+ return `'${value.replace(/'/gu, "'\"'\"'")}'`;
340
+ }
341
+ async function execFileUtf8(command, args, options = {}) {
342
+ try {
343
+ return await execFileAsync(command, [...args], {
344
+ encoding: "utf8",
345
+ ...(options.env ? { env: options.env } : {}),
346
+ maxBuffer: 20 * 1024 * 1024,
347
+ });
348
+ }
349
+ catch (error) {
350
+ const record = error;
351
+ const stderr = typeof record.stderr === "string" ? record.stderr.trim() : "";
352
+ const stdout = typeof record.stdout === "string" ? record.stdout.trim() : "";
353
+ throw new Error([
354
+ `${command} ${args.join(" ")} failed.`,
355
+ stderr,
356
+ stdout,
357
+ record.message,
358
+ ].filter(Boolean).join("\n"));
359
+ }
360
+ }
361
+ function sha256(value) {
362
+ return createHash("sha256").update(value).digest("hex");
363
+ }
@@ -0,0 +1,6 @@
1
+ import type { SurfaceSnapshotFile } from "@workbench-ai/workbench-core";
2
+ import type { LocalProjectSource } from "./project-source.js";
3
+ export declare function localBenchmarkFingerprint(project: LocalProjectSource): string;
4
+ export declare function localSubjectFingerprint(project: LocalProjectSource): string;
5
+ export declare function benchmarkFingerprintForFiles(files: readonly SurfaceSnapshotFile[]): string;
6
+ //# sourceMappingURL=benchmark-fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmark-fingerprint.d.ts","sourceRoot":"","sources":["../src/benchmark-fingerprint.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE9D,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAO7E;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAQ3E;AAED,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,SAAS,mBAAmB,EAAE,GACpC,MAAM,CAgBR"}
@@ -0,0 +1,101 @@
1
+ import { createHash } from "node:crypto";
2
+ export function localBenchmarkFingerprint(project) {
3
+ return benchmarkFingerprintForFiles([
4
+ textFile("benchmark.yaml", project.benchmarkSource),
5
+ ...prefixFiles(project.engineResolveFiles.map(toSurfaceFile), project.engineResolveFingerprintPath),
6
+ ...benchmarkDockerfileFiles(project),
7
+ ...benchmarkAdapterFiles(project),
8
+ ]);
9
+ }
10
+ export function localSubjectFingerprint(project) {
11
+ const hash = createHash("sha256");
12
+ hash.update("workbench-subject-v1\0");
13
+ hash.update(project.subjectSource);
14
+ hash.update("\0runner\0");
15
+ hash.update(JSON.stringify(project.spec.run));
16
+ hashSurfaceFiles(hash, project.subjectFiles);
17
+ return hash.digest("hex");
18
+ }
19
+ export function benchmarkFingerprintForFiles(files) {
20
+ const hash = createHash("sha256");
21
+ hash.update("workbench-benchmark-fingerprint-v1\0");
22
+ for (const file of files
23
+ .map((entry) => ({ ...entry, path: normalizeLocalPath(entry.path) }))
24
+ .sort((left, right) => left.path.localeCompare(right.path))) {
25
+ hash.update(file.path);
26
+ hash.update("\0");
27
+ hash.update(file.encoding ?? "utf8");
28
+ hash.update("\0");
29
+ hash.update(file.executable ? "1" : "0");
30
+ hash.update("\0");
31
+ hash.update(file.content);
32
+ hash.update("\0");
33
+ }
34
+ return hash.digest("hex");
35
+ }
36
+ function benchmarkDockerfileFiles(project) {
37
+ const dockerfilePath = normalizeLocalPath(project.spec.environment.dockerfile);
38
+ return project.dockerfileFiles.filter((file) => normalizeLocalPath(file.path) === dockerfilePath).map(toSurfaceFile);
39
+ }
40
+ function benchmarkAdapterFiles(project) {
41
+ const roots = project.benchmarkAdapterSources.map(normalizeLocalPath);
42
+ const adapterIdRoots = project.benchmarkAdapterIds.map((id) => normalizeLocalPath(`adapters/${id}`));
43
+ const allRoots = [...roots, ...adapterIdRoots];
44
+ if (allRoots.length === 0) {
45
+ return [];
46
+ }
47
+ return project.adapterFiles.filter((file) => allRoots.some((root) => isWithinLocalPath(file.path, root))).map(toSurfaceFile);
48
+ }
49
+ function hashSurfaceFiles(hash, files) {
50
+ for (const file of files.slice().sort((left, right) => left.path.localeCompare(right.path))) {
51
+ hash.update("\0file\0");
52
+ hash.update(file.path);
53
+ hash.update("\0");
54
+ hash.update(file.encoding ?? "utf8");
55
+ hash.update("\0");
56
+ hash.update(file.content);
57
+ hash.update("\0");
58
+ hash.update(file.executable ? "1" : "0");
59
+ }
60
+ }
61
+ function prefixFiles(files, rootPath) {
62
+ const root = normalizeLocalPath(rootPath);
63
+ return files.map((file) => {
64
+ const filePath = normalizeLocalPath(file.path);
65
+ return {
66
+ ...file,
67
+ path: isWithinLocalPath(filePath, root) ? filePath : `${root}/${filePath}`,
68
+ };
69
+ });
70
+ }
71
+ function textFile(filePath, content) {
72
+ return {
73
+ path: filePath,
74
+ kind: "text",
75
+ encoding: "utf8",
76
+ content,
77
+ executable: false,
78
+ };
79
+ }
80
+ function toSurfaceFile(file) {
81
+ return {
82
+ path: file.path,
83
+ kind: "text",
84
+ encoding: file.encoding ?? "utf8",
85
+ content: file.content,
86
+ executable: file.executable ?? false,
87
+ };
88
+ }
89
+ function isWithinLocalPath(filePath, rootPath) {
90
+ const normalizedFile = normalizeLocalPath(filePath);
91
+ const normalizedRoot = normalizeLocalPath(rootPath);
92
+ return normalizedFile === normalizedRoot ||
93
+ normalizedFile.startsWith(`${normalizedRoot}/`);
94
+ }
95
+ function normalizeLocalPath(value) {
96
+ return value
97
+ .replace(/\\/gu, "/")
98
+ .replace(/^\/+/u, "")
99
+ .replace(/\/+/gu, "/")
100
+ .replace(/^(?:\.\/)+/u, "");
101
+ }
@@ -0,0 +1,5 @@
1
+ export declare const LOCAL_DEV_OPEN_LIFECYCLE_NOTE = "Keep this command running while using the local web view; Ctrl-C stops the server and the page will stop working.";
2
+ export declare const HOSTED_WATCH_LIFECYCLE_NOTE: string;
3
+ export declare const rootUsage: string;
4
+ export declare function commandUsage(commandPath: string): string | null;
5
+ //# sourceMappingURL=command-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-model.d.ts","sourceRoot":"","sources":["../src/command-model.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,6BAA6B,sHAC2E,CAAC;AAOtH,eAAO,MAAM,2BAA2B,QAA0C,CAAC;AAsFnF,eAAO,MAAM,SAAS,QAAuB,CAAC;AAmX9C,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE/D"}