@benchsdk/runner 0.3.0 → 0.5.2

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.js CHANGED
@@ -3,14 +3,55 @@ var TaskError = class extends Error {
3
3
  code;
4
4
  data;
5
5
  steps;
6
+ step;
7
+ timeoutMs;
6
8
  constructor(message, opts) {
7
9
  super(message);
8
10
  this.name = "TaskError";
9
11
  this.code = opts?.code;
10
12
  this.data = opts?.data;
11
13
  this.steps = opts?.steps;
14
+ this.step = opts?.step;
15
+ this.timeoutMs = opts?.timeoutMs;
16
+ }
17
+ toString() {
18
+ let s = `[${this.name}${this.code ? ` (${this.code})` : ""}] ${this.message}`;
19
+ if (this.step) {
20
+ s += `
21
+ step: ${this.step}`;
22
+ }
23
+ if (this.timeoutMs !== void 0) {
24
+ s += `
25
+ timeoutMs: ${this.timeoutMs}`;
26
+ }
27
+ if (this.data && Object.keys(this.data).length > 0) {
28
+ s += `
29
+ data: ${JSON.stringify(this.data, null, 2)}`;
30
+ }
31
+ return s;
32
+ }
33
+ };
34
+ var BenchmarkConfigError = class _BenchmarkConfigError extends Error {
35
+ issues;
36
+ constructor(issues) {
37
+ super(_BenchmarkConfigError.formatIssues(issues));
38
+ this.name = "BenchmarkConfigError";
39
+ this.issues = issues;
40
+ }
41
+ static formatIssues(issues) {
42
+ const lines = issues.map((i) => ` - ${i.field}: ${i.message}`);
43
+ return `Invalid benchmark config:
44
+ ${lines.join("\n")}
45
+
46
+ Fix the fields above and try again.`;
12
47
  }
13
48
  };
49
+ function assertFiniteNumber(value, field) {
50
+ if (typeof value !== "number" || !Number.isFinite(value)) {
51
+ throw new Error(`${field} must be a finite number (got ${value})`);
52
+ }
53
+ return value;
54
+ }
14
55
  function assertNonEmptyString(value, field) {
15
56
  if (typeof value !== "string" || value.trim() === "") {
16
57
  throw new Error(`${field} must be a non-empty string`);
@@ -24,18 +65,6 @@ function assertOnlyAllowedKeys(value, allowed, field) {
24
65
  }
25
66
  }
26
67
  }
27
- function assertPositiveInt(value, field) {
28
- if (value === void 0) return;
29
- if (!Number.isInteger(value) || value < 1) {
30
- throw new Error(`${field} must be an integer >= 1 (got ${value})`);
31
- }
32
- }
33
- function assertFiniteNumber(value, field) {
34
- if (typeof value !== "number" || !Number.isFinite(value)) {
35
- throw new Error(`${field} must be a finite number (got ${value})`);
36
- }
37
- return value;
38
- }
39
68
  function validateBenchmarkScoringConfig(scoring, display) {
40
69
  if (!Array.isArray(scoring.metrics) || scoring.metrics.length === 0) {
41
70
  throw new Error("scoring.metrics must be a non-empty array");
@@ -106,154 +135,236 @@ function validateBenchmarkScoringConfig(scoring, display) {
106
135
  throw new Error(`scoring metric weights must sum to 1.0 (got ${totalWeight.toFixed(3)})`);
107
136
  }
108
137
  }
138
+ function validateBenchmarkDisplayConfig(display) {
139
+ if (typeof display !== "object" || display === null || Array.isArray(display)) {
140
+ throw new Error("display must be an object");
141
+ }
142
+ assertOnlyAllowedKeys(display, ["metrics", "steps", "overview"], "display");
143
+ const displayMetricKeys = /* @__PURE__ */ new Set();
144
+ if (display.metrics !== void 0) {
145
+ if (!Array.isArray(display.metrics)) {
146
+ throw new Error("display.metrics must be an array");
147
+ }
148
+ for (let i = 0; i < display.metrics.length; i++) {
149
+ const metric = display.metrics[i];
150
+ if (metric === null || typeof metric !== "object" || Array.isArray(metric)) {
151
+ throw new Error(`display.metrics[${i}] must be an object`);
152
+ }
153
+ assertOnlyAllowedKeys(metric, ["key", "label", "unit", "direction", "decimals", "order"], `display.metrics[${i}]`);
154
+ const key = assertNonEmptyString(metric.key, `display.metrics[${i}].key`);
155
+ if (displayMetricKeys.has(key)) {
156
+ throw new Error(`duplicate display metric key: ${key}`);
157
+ }
158
+ displayMetricKeys.add(key);
159
+ assertNonEmptyString(metric.label, `display.metrics[${i}].label`);
160
+ if (metric.unit !== void 0 && typeof metric.unit !== "string") {
161
+ throw new Error(`display.metrics[${i}].unit must be a string`);
162
+ }
163
+ if (metric.direction !== void 0 && metric.direction !== "higher-better" && metric.direction !== "lower-better") {
164
+ throw new Error(`display.metrics[${i}].direction must be 'higher-better' or 'lower-better'`);
165
+ }
166
+ if (metric.decimals !== void 0 && (!Number.isInteger(metric.decimals) || metric.decimals < 0)) {
167
+ throw new Error(`display.metrics[${i}].decimals must be a non-negative integer`);
168
+ }
169
+ if (metric.order !== void 0 && (!Number.isInteger(metric.order) || metric.order < 0)) {
170
+ throw new Error(`display.metrics[${i}].order must be a non-negative integer`);
171
+ }
172
+ }
173
+ }
174
+ if (display.steps !== void 0) {
175
+ if (!Array.isArray(display.steps)) {
176
+ throw new Error("display.steps must be an array");
177
+ }
178
+ const seenStepKeys = /* @__PURE__ */ new Set();
179
+ for (let i = 0; i < display.steps.length; i++) {
180
+ const step = display.steps[i];
181
+ if (step === null || typeof step !== "object" || Array.isArray(step)) {
182
+ throw new Error(`display.steps[${i}] must be an object`);
183
+ }
184
+ assertOnlyAllowedKeys(step, ["key", "label", "order"], `display.steps[${i}]`);
185
+ const key = assertNonEmptyString(step.key, `display.steps[${i}].key`);
186
+ if (seenStepKeys.has(key)) {
187
+ throw new Error(`duplicate display step key: ${key}`);
188
+ }
189
+ seenStepKeys.add(key);
190
+ assertNonEmptyString(step.label, `display.steps[${i}].label`);
191
+ if (step.order !== void 0 && (!Number.isInteger(step.order) || step.order < 0)) {
192
+ throw new Error(`display.steps[${i}].order must be a non-negative integer`);
193
+ }
194
+ }
195
+ }
196
+ if (display.overview !== void 0) {
197
+ if (typeof display.overview !== "object" || display.overview === null || Array.isArray(display.overview)) {
198
+ throw new Error("display.overview must be an object");
199
+ }
200
+ assertOnlyAllowedKeys(display.overview, ["defaultMetric", "defaultLayout"], "display.overview");
201
+ const { defaultMetric, defaultLayout } = display.overview;
202
+ if (defaultMetric !== void 0) {
203
+ const metric = assertNonEmptyString(defaultMetric, "display.overview.defaultMetric");
204
+ const validDefaultMetrics = new Set(displayMetricKeys);
205
+ validDefaultMetrics.add("compositeScore");
206
+ validDefaultMetrics.add("task");
207
+ if (display.metrics !== void 0 && !validDefaultMetrics.has(metric)) {
208
+ throw new Error(`display.overview.defaultMetric '${metric}' is not declared in display.metrics and is not a known default (compositeScore, task)`);
209
+ }
210
+ }
211
+ if (defaultLayout !== void 0 && !["ranking", "cards", "chart", "leaderboard"].includes(defaultLayout)) {
212
+ throw new Error("display.overview.defaultLayout must be 'ranking', 'cards', 'chart', or 'leaderboard'");
213
+ }
214
+ }
215
+ }
109
216
  function defineBenchmarkConfig(config) {
217
+ const issues = validateBenchmarkConfig(config);
218
+ if (config.scoring !== void 0) {
219
+ try {
220
+ validateBenchmarkScoringConfig(config.scoring, config.display);
221
+ } catch (error) {
222
+ issues.push({
223
+ field: "scoring",
224
+ message: error instanceof Error ? error.message : String(error)
225
+ });
226
+ }
227
+ }
228
+ if (issues.length > 0) {
229
+ throw new BenchmarkConfigError(issues);
230
+ }
231
+ return config;
232
+ }
233
+ function defineTask(task) {
234
+ if (typeof task !== "function") {
235
+ throw new Error("defineTask requires a task function.");
236
+ }
237
+ return task;
238
+ }
239
+ function validateBenchmarkConfig(config) {
240
+ const issues = [];
110
241
  if (!config.benchmarkSlug || typeof config.benchmarkSlug !== "string") {
111
- throw new Error("benchmarkSlug is required");
242
+ issues.push({ field: "benchmarkSlug", message: "is required" });
112
243
  }
113
244
  if (!config.benchmarkName || typeof config.benchmarkName !== "string") {
114
- throw new Error("benchmarkName is required");
245
+ issues.push({ field: "benchmarkName", message: "is required" });
246
+ }
247
+ if (!Array.isArray(config.participants) || config.participants.length === 0) {
248
+ issues.push({ field: "participants", message: "must be a non-empty array" });
249
+ } else {
250
+ const seenParticipants = /* @__PURE__ */ new Set();
251
+ for (let i = 0; i < config.participants.length; i++) {
252
+ const p = config.participants[i];
253
+ if (p === null || typeof p !== "object" || Array.isArray(p)) {
254
+ issues.push({ field: `participants[${i}]`, message: "must be an object" });
255
+ continue;
256
+ }
257
+ const participant = p;
258
+ if (typeof participant.name !== "string" || participant.name.trim() === "") {
259
+ issues.push({ field: `participants[${i}].name`, message: "must be a non-empty string" });
260
+ } else if (seenParticipants.has(participant.name)) {
261
+ issues.push({ field: `participants[${i}].name`, message: `duplicate participant name: ${participant.name}` });
262
+ } else {
263
+ seenParticipants.add(participant.name);
264
+ }
265
+ if (participant.requiredEnvVars !== void 0 && (!Array.isArray(participant.requiredEnvVars) || !participant.requiredEnvVars.every((v) => typeof v === "string"))) {
266
+ issues.push({ field: `participants[${i}].requiredEnvVars`, message: "must be an array of strings" });
267
+ }
268
+ }
115
269
  }
116
270
  if (config.phases !== void 0) {
117
271
  if (config.iterations !== void 0) {
118
- throw new Error("phases and iterations are mutually exclusive");
272
+ issues.push({ field: "iterations", message: "phases and iterations are mutually exclusive" });
119
273
  }
120
274
  if (!Array.isArray(config.phases) || config.phases.length === 0) {
121
- throw new Error("phases must be a non-empty array");
122
- }
123
- const seen = /* @__PURE__ */ new Set();
124
- for (const phase of config.phases) {
125
- if (!phase.name || typeof phase.name !== "string") {
126
- throw new Error("each phase requires a non-empty name");
127
- }
128
- if (seen.has(phase.name)) {
129
- throw new Error(`duplicate phase name: ${phase.name}`);
275
+ issues.push({ field: "phases", message: "must be a non-empty array" });
276
+ } else {
277
+ const seen = /* @__PURE__ */ new Set();
278
+ for (let i = 0; i < config.phases.length; i++) {
279
+ const phase = config.phases[i];
280
+ if (phase === null || typeof phase !== "object" || Array.isArray(phase)) {
281
+ issues.push({ field: `phases[${i}]`, message: "must be an object" });
282
+ continue;
283
+ }
284
+ const phaseObj = phase;
285
+ if (typeof phaseObj.name !== "string" || phaseObj.name.trim() === "") {
286
+ issues.push({ field: `phases[${i}]`, message: "must have a non-empty string name" });
287
+ } else {
288
+ const name = phaseObj.name;
289
+ if (seen.has(name)) {
290
+ issues.push({ field: `phases['${name}']`, message: `duplicate phase name: ${name}` });
291
+ }
292
+ seen.add(name);
293
+ const iterations = phaseObj.iterations;
294
+ if (typeof iterations !== "number" || !Number.isInteger(iterations) || iterations < 1) {
295
+ issues.push({ field: `phases['${name}'].iterations`, message: `must be an integer >= 1 (got ${iterations})` });
296
+ }
297
+ }
130
298
  }
131
- seen.add(phase.name);
132
- assertPositiveInt(phase.iterations, `phase '${phase.name}' iterations`);
133
299
  }
134
300
  }
135
- assertPositiveInt(config.iterations, "iterations");
136
- assertPositiveInt(config.concurrency, "concurrency");
301
+ if (config.iterations !== void 0 && (!Number.isInteger(config.iterations) || config.iterations < 1)) {
302
+ issues.push({ field: "iterations", message: `must be an integer >= 1 (got ${config.iterations})` });
303
+ }
304
+ if (config.concurrency !== void 0 && (!Number.isInteger(config.concurrency) || config.concurrency < 1)) {
305
+ issues.push({ field: "concurrency", message: `must be an integer >= 1 (got ${config.concurrency})` });
306
+ }
137
307
  if (config.staggerDelayMs !== void 0 && (!Number.isFinite(config.staggerDelayMs) || config.staggerDelayMs < 0)) {
138
- throw new Error(`staggerDelayMs must be a number >= 0 (got ${config.staggerDelayMs})`);
308
+ issues.push({ field: "staggerDelayMs", message: `must be a number >= 0 (got ${config.staggerDelayMs})` });
139
309
  }
140
310
  if (config.groupBy !== void 0 && config.groupBy !== "participant" && config.groupBy !== "round") {
141
- throw new Error(`groupBy must be 'participant' or 'round' (got ${config.groupBy})`);
311
+ issues.push({ field: "groupBy", message: `must be 'participant' or 'round' (got ${config.groupBy})` });
142
312
  }
143
313
  if (config.shapes !== void 0) {
144
- for (const [shapeName, shape] of Object.entries(config.shapes)) {
145
- if (!shape.slug || !/^[a-z0-9][a-z0-9-]*$/.test(shape.slug)) {
146
- throw new Error(`shape '${shapeName}' needs a lowercase slug (got ${JSON.stringify(shape.slug)})`);
147
- }
148
- if (shape.name !== void 0 && (typeof shape.name !== "string" || shape.name.trim() === "")) {
149
- throw new Error(`shape '${shapeName}' name must be a non-empty string`);
150
- }
151
- if (shape.staggerDelayMs !== void 0 && (!Number.isFinite(shape.staggerDelayMs) || shape.staggerDelayMs < 0)) {
152
- throw new Error(`shape '${shapeName}' staggerDelayMs must be a number >= 0 (got ${shape.staggerDelayMs})`);
314
+ if (typeof config.shapes !== "object" || config.shapes === null || Array.isArray(config.shapes)) {
315
+ issues.push({ field: "shapes", message: "must be a plain object" });
316
+ } else {
317
+ for (const [shapeName, shape] of Object.entries(config.shapes)) {
318
+ if (shape === null || typeof shape !== "object" || Array.isArray(shape)) {
319
+ issues.push({ field: `shapes['${shapeName}']`, message: "must be an object" });
320
+ continue;
321
+ }
322
+ const shapeObj = shape;
323
+ const slug = shapeObj.slug;
324
+ if (typeof slug !== "string" || slug === "" || !/^[a-z0-9][a-z0-9-]*$/.test(slug)) {
325
+ issues.push({ field: `shapes['${shapeName}'].slug`, message: `needs a lowercase slug (got ${JSON.stringify(slug)})` });
326
+ }
327
+ const name = shapeObj.name;
328
+ if (name !== void 0 && (typeof name !== "string" || name.trim() === "")) {
329
+ issues.push({ field: `shapes['${shapeName}'].name`, message: "must be a non-empty string" });
330
+ }
331
+ const staggerDelayMs = shapeObj.staggerDelayMs;
332
+ if (staggerDelayMs !== void 0 && (typeof staggerDelayMs !== "number" || !Number.isFinite(staggerDelayMs) || staggerDelayMs < 0)) {
333
+ issues.push({ field: `shapes['${shapeName}'].staggerDelayMs`, message: `must be a number >= 0 (got ${staggerDelayMs})` });
334
+ }
153
335
  }
154
336
  }
155
337
  }
156
338
  if (config.dimensions !== void 0) {
157
339
  if (config.dimensions === null || typeof config.dimensions !== "object" || Array.isArray(config.dimensions)) {
158
- throw new Error("dimensions must be a plain object");
340
+ issues.push({ field: "dimensions", message: "must be a plain object" });
159
341
  }
160
342
  }
161
- if (config.scoring !== void 0) {
162
- validateBenchmarkScoringConfig(config.scoring, config.display);
163
- }
164
343
  if (config.customCliFlags !== void 0) {
165
344
  if (!Array.isArray(config.customCliFlags) || !config.customCliFlags.every((f) => typeof f === "string" && f.startsWith("--"))) {
166
- throw new Error('customCliFlags must be an array of strings starting with "--"');
345
+ issues.push({ field: "customCliFlags", message: 'must be an array of strings starting with "--"' });
167
346
  }
168
347
  }
169
348
  if (config.display !== void 0) {
170
- if (typeof config.display !== "object" || config.display === null || Array.isArray(config.display)) {
171
- throw new Error("display must be an object");
172
- }
173
- assertOnlyAllowedKeys(config.display, ["metrics", "steps", "overview"], "display");
174
- const displayMetricKeys = /* @__PURE__ */ new Set();
175
- if (config.display.metrics !== void 0) {
176
- if (!Array.isArray(config.display.metrics)) {
177
- throw new Error("display.metrics must be an array");
178
- }
179
- for (let i = 0; i < config.display.metrics.length; i++) {
180
- const metric = config.display.metrics[i];
181
- if (metric === null || typeof metric !== "object" || Array.isArray(metric)) {
182
- throw new Error(`display.metrics[${i}] must be an object`);
183
- }
184
- assertOnlyAllowedKeys(metric, ["key", "label", "unit", "direction", "decimals", "order"], `display.metrics[${i}]`);
185
- const key = assertNonEmptyString(metric.key, `display.metrics[${i}].key`);
186
- if (displayMetricKeys.has(key)) {
187
- throw new Error(`duplicate display metric key: ${key}`);
188
- }
189
- displayMetricKeys.add(key);
190
- assertNonEmptyString(metric.label, `display.metrics[${i}].label`);
191
- if (metric.unit !== void 0 && typeof metric.unit !== "string") {
192
- throw new Error(`display.metrics[${i}].unit must be a string`);
193
- }
194
- if (metric.direction !== void 0 && metric.direction !== "higher-better" && metric.direction !== "lower-better") {
195
- throw new Error(`display.metrics[${i}].direction must be 'higher-better' or 'lower-better'`);
196
- }
197
- if (metric.decimals !== void 0 && (!Number.isInteger(metric.decimals) || metric.decimals < 0)) {
198
- throw new Error(`display.metrics[${i}].decimals must be a non-negative integer`);
199
- }
200
- if (metric.order !== void 0 && (!Number.isInteger(metric.order) || metric.order < 0)) {
201
- throw new Error(`display.metrics[${i}].order must be a non-negative integer`);
202
- }
203
- }
204
- }
205
- if (config.display.steps !== void 0) {
206
- if (!Array.isArray(config.display.steps)) {
207
- throw new Error("display.steps must be an array");
208
- }
209
- const seenStepKeys = /* @__PURE__ */ new Set();
210
- for (let i = 0; i < config.display.steps.length; i++) {
211
- const step = config.display.steps[i];
212
- if (step === null || typeof step !== "object" || Array.isArray(step)) {
213
- throw new Error(`display.steps[${i}] must be an object`);
214
- }
215
- assertOnlyAllowedKeys(step, ["key", "label", "order"], `display.steps[${i}]`);
216
- const key = assertNonEmptyString(step.key, `display.steps[${i}].key`);
217
- if (seenStepKeys.has(key)) {
218
- throw new Error(`duplicate display step key: ${key}`);
219
- }
220
- seenStepKeys.add(key);
221
- assertNonEmptyString(step.label, `display.steps[${i}].label`);
222
- if (step.order !== void 0 && (!Number.isInteger(step.order) || step.order < 0)) {
223
- throw new Error(`display.steps[${i}].order must be a non-negative integer`);
224
- }
225
- }
226
- }
227
- if (config.display.overview !== void 0) {
228
- if (typeof config.display.overview !== "object" || config.display.overview === null || Array.isArray(config.display.overview)) {
229
- throw new Error("display.overview must be an object");
230
- }
231
- assertOnlyAllowedKeys(config.display.overview, ["defaultMetric", "defaultLayout"], "display.overview");
232
- const { defaultMetric, defaultLayout } = config.display.overview;
233
- if (defaultMetric !== void 0) {
234
- const metric = assertNonEmptyString(defaultMetric, "display.overview.defaultMetric");
235
- const validDefaultMetrics = new Set(displayMetricKeys);
236
- validDefaultMetrics.add("compositeScore");
237
- validDefaultMetrics.add("task");
238
- if (config.display.metrics !== void 0 && !validDefaultMetrics.has(metric)) {
239
- throw new Error(`display.overview.defaultMetric '${metric}' is not declared in display.metrics and is not a known default (compositeScore, task)`);
240
- }
241
- }
242
- if (defaultLayout !== void 0 && !["ranking", "cards", "chart", "leaderboard"].includes(defaultLayout)) {
243
- throw new Error("display.overview.defaultLayout must be 'ranking', 'cards', 'chart', or 'leaderboard'");
244
- }
349
+ try {
350
+ validateBenchmarkDisplayConfig(config.display);
351
+ } catch (error) {
352
+ issues.push({
353
+ field: "display",
354
+ message: error instanceof Error ? error.message : String(error)
355
+ });
245
356
  }
246
357
  }
247
358
  if (config.display?.overview?.defaultMetric === "compositeScore" && config.scoring === void 0 && config.onScore === void 0) {
248
- throw new Error("display.overview.defaultMetric cannot be 'compositeScore' without config.scoring or config.onScore");
359
+ issues.push({
360
+ field: "display.overview.defaultMetric",
361
+ message: "cannot be 'compositeScore' without config.scoring or config.onScore"
362
+ });
249
363
  }
250
- return config;
364
+ return issues;
251
365
  }
252
- function defineTask(task) {
253
- if (typeof task !== "function") {
254
- throw new Error("defineTask requires a task function.");
255
- }
256
- return task;
366
+ function defineOnComplete(onComplete) {
367
+ return onComplete;
257
368
  }
258
369
 
259
370
  // src/no-available-participants.ts
@@ -271,7 +382,7 @@ var NoAvailableParticipantsError = class extends Error {
271
382
  // src/runner.ts
272
383
  import { execSync } from "child_process";
273
384
  import os from "os";
274
- import { createBenchmarkClient } from "@benchsdk/api";
385
+ import { createBenchmarkClient, BenchmarkApiError } from "@benchsdk/api";
275
386
  import { resolveAuth } from "@benchsdk/cli";
276
387
  import {
277
388
  BenchmarkReporter,
@@ -545,12 +656,18 @@ function isStepOutcome(value) {
545
656
  if (!keys.every((k) => STEP_OUTCOME_KEYS.has(k))) return false;
546
657
  return typeof o.stdout === "string" || typeof o.stderr === "string" || typeof o.error === "string";
547
658
  }
548
- function withTimeout(promise, ms, name) {
659
+ function withTimeout(promise, { stepName, timeoutMs, participantSlug }) {
549
660
  return new Promise((resolve2, reject) => {
550
- const timer = setTimeout(
551
- () => reject(new TaskError(`Step "${name}" timed out after ${ms}ms`, { code: "step_timeout" })),
552
- ms
553
- );
661
+ const timer = setTimeout(() => {
662
+ const participant = participantSlug ? ` for participant "${participantSlug}"` : "";
663
+ reject(
664
+ new TaskError(`Step "${stepName}" timed out after ${timeoutMs}ms${participant}`, {
665
+ code: "step_timeout",
666
+ step: stepName,
667
+ timeoutMs
668
+ })
669
+ );
670
+ }, timeoutMs);
554
671
  promise.then(
555
672
  (value) => {
556
673
  clearTimeout(timer);
@@ -563,20 +680,23 @@ function withTimeout(promise, ms, name) {
563
680
  );
564
681
  });
565
682
  }
566
- async function runStepInvocations(name, fn, options) {
567
- const requestedConcurrency = options?.concurrency;
568
- if (requestedConcurrency !== void 0 && (!Number.isInteger(requestedConcurrency) || requestedConcurrency < 1)) {
569
- throw new Error(`step "${name}" concurrency must be an integer >= 1 (got ${requestedConcurrency})`);
683
+ async function runStepInvocations(name, fn, options, participantSlug) {
684
+ if (options?.concurrency !== void 0) {
685
+ console.warn(`[benchsdk] step "${name}" option "concurrency" is deprecated; use "parallelInvocations"`);
686
+ }
687
+ const requestedParallelism = options?.parallelInvocations ?? options?.concurrency;
688
+ if (requestedParallelism !== void 0 && (!Number.isInteger(requestedParallelism) || requestedParallelism < 1)) {
689
+ throw new Error(`step "${name}" parallelInvocations must be an integer >= 1 (got ${requestedParallelism})`);
570
690
  }
571
691
  const timeoutMs = options?.timeoutMs;
572
692
  if (timeoutMs !== void 0 && (!Number.isFinite(timeoutMs) || timeoutMs < 0)) {
573
693
  throw new Error(`step "${name}" timeoutMs must be a number >= 0 (got ${timeoutMs})`);
574
694
  }
575
- const count = requestedConcurrency ?? 1;
695
+ const count = requestedParallelism ?? 1;
576
696
  const invocations = Array.from({ length: count }, () => {
577
697
  const promise = Promise.resolve().then(() => fn());
578
698
  if (timeoutMs === void 0) return promise;
579
- return withTimeout(promise, timeoutMs, name);
699
+ return withTimeout(promise, { stepName: name, timeoutMs, participantSlug });
580
700
  });
581
701
  if (count === 1) {
582
702
  return invocations[0];
@@ -594,14 +714,14 @@ async function runStepInvocations(name, fn, options) {
594
714
  if (firstError !== void 0) throw firstError;
595
715
  return results;
596
716
  }
597
- async function runStepWithClient(clientStep, name, fn, options) {
598
- const { concurrency: runnerConcurrency, timeoutMs, ...clientOptions } = options ?? {};
717
+ async function runStepWithClient(clientStep, name, fn, options, participantSlug) {
718
+ const { parallelInvocations: runnerParallelism, concurrency: deprecatedConcurrency, timeoutMs, ...clientOptions } = options ?? {};
599
719
  const clientStepOptions = {
600
720
  ...clientOptions,
601
721
  timeoutMs,
602
- stepConcurrency: runnerConcurrency
722
+ stepConcurrency: runnerParallelism ?? deprecatedConcurrency
603
723
  };
604
- const result = await clientStep(name, () => runStepInvocations(name, fn, options), clientStepOptions);
724
+ const result = await clientStep(name, () => runStepInvocations(name, fn, options, participantSlug), clientStepOptions);
605
725
  return result;
606
726
  }
607
727
  function parseCliArgs(argv, allowedCustomFlags) {
@@ -769,7 +889,9 @@ function defaultOnResult(record, meta) {
769
889
  const data = record.data && Object.keys(record.data).length > 0 ? ` ${JSON.stringify(record.data)}` : "";
770
890
  console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: success${data}`);
771
891
  } else {
772
- console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: FAILED \u2014 ${record.errorCode ?? "unknown error"}`);
892
+ const detail = record.data?.errorMessage ?? record.data?.error;
893
+ const suffix = typeof detail === "string" && detail.length > 0 ? `: ${detail}` : "";
894
+ console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: FAILED \u2014 ${record.errorCode ?? "unknown error"}${suffix}`);
773
895
  }
774
896
  }
775
897
  function resolveShape(config, shapeName) {
@@ -810,7 +932,23 @@ function resolveParticipants(config, resolved) {
810
932
  if (available.length === 0) throw new NoAvailableParticipantsError(skipped);
811
933
  return available;
812
934
  }
813
- function runConfigToJson(config, resolved, participants) {
935
+ function resolveTriggerSource(env = process.env) {
936
+ const source = env.BENCH_TRIGGER_SOURCE?.trim();
937
+ if (source) return source;
938
+ return env.GITHUB_EVENT_NAME?.trim() || "manual";
939
+ }
940
+ function triggerToJson(env = process.env) {
941
+ const requestedBy = env.BENCH_TRIGGER_REQUESTED_BY?.trim();
942
+ const requestId = env.BENCH_TRIGGER_REQUEST_ID?.trim();
943
+ const event = env.GITHUB_EVENT_NAME?.trim();
944
+ return {
945
+ source: resolveTriggerSource(env),
946
+ ...event ? { event } : {},
947
+ ...requestedBy ? { requestedBy } : {},
948
+ ...requestId ? { requestId } : {}
949
+ };
950
+ }
951
+ function runConfigToJson(config, resolved, participants, env = process.env) {
814
952
  const phases = config.phases?.map((phase) => ({
815
953
  name: phase.name,
816
954
  iterations: resolved.phaseIterations ?? phase.iterations
@@ -826,24 +964,38 @@ function runConfigToJson(config, resolved, participants) {
826
964
  groupBy: resolved.groupBy,
827
965
  ...config.dimensions ? { dimensions: config.dimensions } : {},
828
966
  ...config.scoring ? { scoring: config.scoring } : {},
829
- participants
967
+ participants,
968
+ trigger: triggerToJson(env)
830
969
  };
831
970
  return JSON.parse(JSON.stringify(runConfig));
832
971
  }
833
- async function runBenchmark(fileConfig, task, argv = []) {
972
+ async function runBenchmark(fileConfig, task, argv = [], options = {}) {
834
973
  const args = parseCliArgs(argv, fileConfig.customCliFlags);
835
974
  const noIngest = args.noIngest ?? isEnvNoIngest();
836
975
  const shaped = applyShape(fileConfig, resolveShape(fileConfig, args.shape));
837
976
  const config = applyIdentityOverrides(shaped, args);
838
977
  const resolved = mergeConfig(config, args);
839
- const auth = await resolveAuth();
840
- const client = createBenchmarkClient({
841
- baseUrl: auth.apiBaseUrl,
842
- apiKey: auth.apiKey,
843
- token: auth.token,
844
- orgSlug: auth.orgSlug,
845
- orgId: auth.orgId
846
- });
978
+ let baseUrl = "";
979
+ let apiKey = "";
980
+ let token;
981
+ let orgSlug;
982
+ let orgId;
983
+ let client = null;
984
+ const auth = noIngest ? await resolveAuth({ baseUrl: options.baseUrl, apiKey: options.apiKey }).catch(() => null) : await resolveAuth({ baseUrl: options.baseUrl, apiKey: options.apiKey });
985
+ if (auth) {
986
+ baseUrl = auth.apiBaseUrl;
987
+ apiKey = auth.apiKey ?? "";
988
+ token = auth.token;
989
+ orgSlug = auth.orgSlug;
990
+ orgId = auth.orgId;
991
+ client = createBenchmarkClient({
992
+ baseUrl: auth.apiBaseUrl,
993
+ apiKey: auth.apiKey,
994
+ token: auth.token,
995
+ orgSlug: auth.orgSlug,
996
+ orgId: auth.orgId
997
+ });
998
+ }
847
999
  const available = resolveParticipants(config, resolved);
848
1000
  const schedule = buildSchedule(config, resolved, task);
849
1001
  const totalTasks = schedule.length;
@@ -864,15 +1016,26 @@ async function runBenchmark(fileConfig, task, argv = []) {
864
1016
  runId = "no-ingest";
865
1017
  dashboardUrl = "";
866
1018
  } else {
867
- if (identityIsOurs) {
1019
+ {
868
1020
  const benchmarkConfig = {
869
1021
  ...config.scoring ? { scoring: config.scoring } : {},
870
1022
  ...config.display ? { display: config.display } : {}
871
1023
  };
872
- await client.upsertBenchmark(config.benchmarkSlug, {
873
- name: config.benchmarkName,
874
- ...Object.keys(benchmarkConfig).length > 0 ? { config: benchmarkConfig } : {}
875
- });
1024
+ let initializeTarget = identityIsOurs;
1025
+ if (!initializeTarget) {
1026
+ try {
1027
+ await client.getBenchmark(config.benchmarkSlug);
1028
+ } catch (error) {
1029
+ if (!(error instanceof BenchmarkApiError && error.status === 404)) throw error;
1030
+ initializeTarget = true;
1031
+ }
1032
+ }
1033
+ const upsertInput = {};
1034
+ if (initializeTarget) {
1035
+ upsertInput.name = config.benchmarkName;
1036
+ if (Object.keys(benchmarkConfig).length > 0) upsertInput.config = benchmarkConfig;
1037
+ }
1038
+ await client.upsertBenchmark(config.benchmarkSlug, upsertInput);
876
1039
  }
877
1040
  const runConfig = client ? runConfigToJson(config, resolved, available.map((p) => p.name)) : {};
878
1041
  if (args.runKey) {
@@ -881,7 +1044,7 @@ async function runBenchmark(fileConfig, task, argv = []) {
881
1044
  config: runConfig
882
1045
  });
883
1046
  runId = run2.id;
884
- dashboardUrl = dashboardUrlFor(auth.apiBaseUrl, organizationSlug, config.benchmarkSlug, run2.id);
1047
+ dashboardUrl = dashboardUrlFor(baseUrl, organizationSlug, config.benchmarkSlug, run2.id);
885
1048
  for (const participant of available) {
886
1049
  await client.upsertParticipant(config.benchmarkSlug, runId, participant.name, { totalTasks });
887
1050
  }
@@ -896,7 +1059,7 @@ async function runBenchmark(fileConfig, task, argv = []) {
896
1059
  config: runConfig
897
1060
  });
898
1061
  runId = run2.id;
899
- dashboardUrl = dashboardUrlFor(auth.apiBaseUrl, organizationSlug, config.benchmarkSlug, run2.id);
1062
+ dashboardUrl = dashboardUrlFor(baseUrl, organizationSlug, config.benchmarkSlug, run2.id);
900
1063
  console.log(`Run created: ${run2.name} (${runId})`);
901
1064
  console.log(`View at: ${dashboardUrl}
902
1065
  `);
@@ -905,7 +1068,7 @@ async function runBenchmark(fileConfig, task, argv = []) {
905
1068
  const onResult = defaultOnResult;
906
1069
  let participantRecords;
907
1070
  if (resolved.groupBy === "round") {
908
- participantRecords = await runGroupedByRound(config, schedule, available, resolved, client, runId, auth.apiBaseUrl, auth.apiKey, auth.token, auth.orgSlug, auth.orgId, onResult, noIngest);
1071
+ participantRecords = await runGroupedByRound(config, schedule, available, resolved, client, runId, baseUrl, apiKey, token, orgSlug, orgId, onResult, noIngest);
909
1072
  } else {
910
1073
  participantRecords = await runGroupedByParticipant(config, schedule, available, resolved, client, runId, onResult, noIngest);
911
1074
  }
@@ -916,14 +1079,14 @@ async function runBenchmark(fileConfig, task, argv = []) {
916
1079
  participants: participantRecords,
917
1080
  config: resolved
918
1081
  };
919
- if (!noIngest && (config.onScore || config.scoring)) {
1082
+ if (!noIngest && client && (config.onScore || config.scoring)) {
920
1083
  try {
921
1084
  const spec = config.onScore ? await config.onScore(lowerIsBetter, higherIsBetter) : scoringConfigToSpec(config.scoring, config.dimensions, config.display);
922
1085
  const scored = score(outcome, spec, config.display?.metrics);
923
1086
  const run2 = {
924
1087
  gitSha: process.env.GITHUB_SHA ?? getGitSha(),
925
1088
  gitRef: process.env.GITHUB_REF_NAME ?? process.env.GITHUB_REF ?? getGitRef(),
926
- triggeredBy: process.env.GITHUB_EVENT_NAME ?? "manual",
1089
+ triggeredBy: resolveTriggerSource(),
927
1090
  nodeVersion: process.version,
928
1091
  platform: os.platform(),
929
1092
  arch: os.arch()
@@ -942,6 +1105,22 @@ async function runBenchmark(fileConfig, task, argv = []) {
942
1105
  if (config.onComplete) await config.onComplete(outcome);
943
1106
  return outcome;
944
1107
  }
1108
+ async function runBenchmarkWorker(options) {
1109
+ const config = defineBenchmarkConfig({
1110
+ benchmarkSlug: options.benchmarkSlug,
1111
+ benchmarkName: options.benchmarkName ?? options.benchmarkSlug,
1112
+ participants: [options.participant],
1113
+ iterations: options.iterations ?? 1,
1114
+ concurrency: options.concurrency ?? 1,
1115
+ staggerDelayMs: options.staggerDelayMs ?? 0,
1116
+ groupBy: options.groupBy ?? "participant",
1117
+ defaultProviders: [options.participant.name]
1118
+ });
1119
+ const argv = [];
1120
+ if (options.runKey) argv.push("--run-key", options.runKey);
1121
+ if (options.noIngest) argv.push("--dry-run");
1122
+ return runBenchmark(config, options.task, argv);
1123
+ }
945
1124
  function getGitSha() {
946
1125
  if (process.env.GITHUB_SHA) return process.env.GITHUB_SHA;
947
1126
  try {
@@ -1016,7 +1195,7 @@ async function runGroupedByParticipant(config, schedule, available, resolved, cl
1016
1195
  participant,
1017
1196
  taskIndex: scheduleIndex,
1018
1197
  phase: slot.phase,
1019
- step: (name, fn, options) => runStepWithClient(ctx.step, name, fn, options),
1198
+ step: (name, fn, options) => runStepWithClient(ctx.step, name, fn, options, participant.name),
1020
1199
  measure: ctx.measure,
1021
1200
  log: ctx.log
1022
1201
  });
@@ -1173,12 +1352,13 @@ async function runTaskRecord(task, participant, scheduleIndex, taskIndex, phase,
1173
1352
  completedAt: new Date(stepStartedAtMs).toISOString(),
1174
1353
  latencyMs: 0
1175
1354
  };
1176
- if (options?.concurrency !== void 0) stepRecord.concurrency = options.concurrency;
1355
+ const requestedParallelism = options?.parallelInvocations ?? options?.concurrency;
1356
+ if (requestedParallelism !== void 0) stepRecord.concurrency = requestedParallelism;
1177
1357
  if (options?.timeoutMs !== void 0) stepRecord.timeoutMs = options.timeoutMs;
1178
1358
  const previousStep = activeStep;
1179
1359
  activeStep = stepRecord;
1180
1360
  try {
1181
- const result2 = await runStepInvocations(name, fn, options);
1361
+ const result2 = await runStepInvocations(name, fn, options, participant.name);
1182
1362
  const outcome = options?.captureOutput !== false && !Array.isArray(result2) && isStepOutcome(result2) ? result2 : {};
1183
1363
  logBuffer.step(taskIndex, name, outcome);
1184
1364
  return result2;
@@ -1247,17 +1427,145 @@ async function runTaskRecord(task, participant, scheduleIndex, taskIndex, phase,
1247
1427
  // src/cli.ts
1248
1428
  import { resolve } from "path";
1249
1429
  import { pathToFileURL } from "url";
1250
- import { run as runPlatformCli } from "@benchsdk/cli";
1251
- var USAGE = 'Usage:\n bench run <file.bench.ts> [--shape name] [--provider a,b] [--run-key key]\n [--benchmark slug] [--name "My benchmark"]\n [--iterations N] [--concurrency N] [--stagger-delay-ms N] [--group-by participant|round]\n [--no-ingest | --dry-run]';
1430
+ import { run as runPlatformCli, resolveAuth as resolveAuth2 } from "@benchsdk/cli";
1431
+ import { createBenchmarkClient as createBenchmarkClient2 } from "@benchsdk/api";
1432
+ import { filterParticipantsByEnv as filterParticipantsByEnv2, selectParticipants as selectParticipants2 } from "@benchsdk/worker";
1433
+ var USAGE = 'Usage:\n bench run <file.bench.ts> [--shape name] [--provider a,b] [--run-key key]\n [--benchmark slug] [--name "My benchmark"]\n [--iterations N] [--concurrency N] [--stagger-delay-ms N] [--group-by participant|round]\n [--no-ingest | --dry-run] [--check]\n bench check <file.bench.ts> [--base-url <url>] [--api-key <key>]';
1252
1434
  function isBenchmarkConfig(value) {
1253
1435
  if (typeof value !== "object" || value === null) return false;
1254
1436
  const candidate = value;
1255
1437
  return typeof candidate.benchmarkSlug === "string" && Array.isArray(candidate.participants);
1256
1438
  }
1439
+ function shiftFlag(argv, name) {
1440
+ const prefix = `--${name}`;
1441
+ const prefixEq = `${prefix}=`;
1442
+ const result = [];
1443
+ let value;
1444
+ for (let i = 0; i < argv.length; i++) {
1445
+ const arg = argv[i];
1446
+ if (arg === prefix) {
1447
+ const next = argv[++i];
1448
+ if (!next || next.startsWith("--")) throw new Error(USAGE);
1449
+ value = next;
1450
+ continue;
1451
+ }
1452
+ if (arg.startsWith(prefixEq)) {
1453
+ const eqValue = arg.slice(prefixEq.length);
1454
+ if (!eqValue) throw new Error(USAGE);
1455
+ value = eqValue;
1456
+ continue;
1457
+ }
1458
+ result.push(arg);
1459
+ }
1460
+ return { value, argv: result };
1461
+ }
1462
+ function shiftPlatformFlags(flags) {
1463
+ const { value: baseUrl, argv: withoutBaseUrl } = shiftFlag(flags, "base-url");
1464
+ const { value: apiKey, argv: rest } = shiftFlag(withoutBaseUrl, "api-key");
1465
+ return { baseUrl, apiKey, flags: rest };
1466
+ }
1467
+ async function runCheck(argv) {
1468
+ const [command, ...rest] = argv;
1469
+ const [file, ...flags] = rest;
1470
+ if (command !== "check" || !file || file.startsWith("-")) throw new Error(USAGE);
1471
+ const mod = await import(pathToFileURL(resolve(process.cwd(), file)).href);
1472
+ const config = mod.config;
1473
+ const task = mod.task ?? mod.default;
1474
+ if (!isBenchmarkConfig(config)) {
1475
+ throw new Error(`${file} must export a \`config\` created with defineBenchmarkConfig (with participants).`);
1476
+ }
1477
+ if (typeof task !== "function") {
1478
+ throw new Error(`${file} must export a \`task\` created with defineTask.`);
1479
+ }
1480
+ const cfg = config;
1481
+ const configIssues = validateBenchmarkConfig(cfg);
1482
+ if (configIssues.length > 0) {
1483
+ throw new BenchmarkConfigError(configIssues);
1484
+ }
1485
+ const { baseUrl, apiKey, flags: runnerFlags } = shiftPlatformFlags(flags);
1486
+ const parsed = parseCliArgs(runnerFlags, cfg.customCliFlags ?? []);
1487
+ resolveShape(cfg, parsed.shape);
1488
+ const dryRun = parsed.noIngest ?? false;
1489
+ let client;
1490
+ let apiOk = dryRun;
1491
+ let auth = null;
1492
+ if (!dryRun) {
1493
+ try {
1494
+ auth = await resolveAuth2({ baseUrl, apiKey });
1495
+ client = createBenchmarkClient2({
1496
+ baseUrl: auth.apiBaseUrl,
1497
+ apiKey: auth.apiKey,
1498
+ token: auth.token,
1499
+ orgSlug: auth.orgSlug,
1500
+ orgId: auth.orgId
1501
+ });
1502
+ await client.listBenchmarks({ limit: 1 });
1503
+ apiOk = true;
1504
+ } catch (err) {
1505
+ const message = err instanceof Error ? err.message : String(err);
1506
+ console.warn(`[benchsdk] API connectivity check failed: ${message}`);
1507
+ }
1508
+ }
1509
+ const effectiveProviderNames = parsed.providers ?? cfg.defaultProviders;
1510
+ let selected;
1511
+ try {
1512
+ selected = selectParticipants2(cfg.participants, effectiveProviderNames);
1513
+ } catch (err) {
1514
+ throw new Error(`Participant selection failed: ${err instanceof Error ? err.message : err}`);
1515
+ }
1516
+ const { available, skipped } = filterParticipantsByEnv2(selected);
1517
+ let scoringOk = true;
1518
+ if (cfg.onScore) {
1519
+ try {
1520
+ const spec = await cfg.onScore(lowerIsBetter, higherIsBetter);
1521
+ validateScoringSpec(spec);
1522
+ } catch (err) {
1523
+ scoringOk = false;
1524
+ const message = err instanceof Error ? err.message : String(err);
1525
+ console.warn(`[benchsdk] Scoring validation failed: ${message}`);
1526
+ }
1527
+ } else if (cfg.scoring) {
1528
+ try {
1529
+ const spec = scoringConfigToSpec(cfg.scoring, cfg.dimensions);
1530
+ validateScoringSpec(spec);
1531
+ } catch (err) {
1532
+ scoringOk = false;
1533
+ const message = err instanceof Error ? err.message : String(err);
1534
+ console.warn(`[benchsdk] Scoring validation failed: ${message}`);
1535
+ }
1536
+ }
1537
+ const missingPlatformAuth = dryRun ? [] : auth ? [] : [["BENCHMARKS_PLATFORM_API_KEY or BENCHMARKS_PLATFORM_TOKEN", void 0]];
1538
+ for (const [name] of missingPlatformAuth) {
1539
+ console.warn(`[benchsdk] ${name} is not set`);
1540
+ }
1541
+ const report = {
1542
+ file,
1543
+ benchmarkSlug: cfg.benchmarkSlug,
1544
+ apiOk,
1545
+ envOk: dryRun || missingPlatformAuth.length === 0,
1546
+ participants: {
1547
+ requested: selected.map((p) => p.name),
1548
+ available: available.map((p) => p.name),
1549
+ skipped: skipped.map((s) => ({ name: s.name, missing: s.missing }))
1550
+ },
1551
+ scoringOk: cfg.scoring || cfg.onScore ? scoringOk : void 0
1552
+ };
1553
+ console.log(JSON.stringify(report, null, 2));
1554
+ const authFailure = !dryRun && missingPlatformAuth.length > 0;
1555
+ if (!apiOk || available.length === 0 || scoringOk === false || authFailure) {
1556
+ throw new Error("Benchmark check failed. See warnings above for details.");
1557
+ }
1558
+ }
1257
1559
  async function runBenchmarkFile(argv) {
1258
1560
  const [command, ...rest] = argv;
1259
1561
  const [file, ...flags] = rest;
1260
1562
  if (command !== "run" || !file || file.startsWith("-")) throw new Error(USAGE);
1563
+ const check = flags.includes("--check") || flags.includes("--validate");
1564
+ if (check) {
1565
+ const checkFlags = flags.filter((f) => f !== "--check" && f !== "--validate");
1566
+ return runCheck(["check", file, ...checkFlags]);
1567
+ }
1568
+ const { baseUrl, apiKey, flags: runnerFlags } = shiftPlatformFlags(flags);
1261
1569
  const mod = await import(pathToFileURL(resolve(process.cwd(), file)).href);
1262
1570
  const config = mod.config;
1263
1571
  const task = mod.task ?? mod.default;
@@ -1267,43 +1575,84 @@ async function runBenchmarkFile(argv) {
1267
1575
  if (typeof task !== "function") {
1268
1576
  throw new Error(`${file} must export a \`task\` created with defineTask.`);
1269
1577
  }
1270
- await runBenchmark(config, task, flags);
1578
+ const envFlags = [];
1579
+ if (process.env.BENCHMARK_SLUG) {
1580
+ envFlags.push("--benchmark", process.env.BENCHMARK_SLUG);
1581
+ }
1582
+ if (process.env.BENCHMARK_NAME) {
1583
+ envFlags.push("--name", process.env.BENCHMARK_NAME);
1584
+ }
1585
+ await runBenchmark(
1586
+ config,
1587
+ task,
1588
+ [...envFlags, ...runnerFlags],
1589
+ { baseUrl, apiKey }
1590
+ );
1271
1591
  }
1272
1592
  async function run(argv) {
1273
- if (argv[0] !== "run") {
1274
- return runPlatformCli(argv);
1275
- }
1593
+ const [command, ...rest] = argv;
1276
1594
  try {
1277
- await runBenchmarkFile(argv);
1595
+ if (command === "run") {
1596
+ await runBenchmarkFile(argv);
1597
+ } else if (command === "check") {
1598
+ await runCheck(argv);
1599
+ } else {
1600
+ return runPlatformCli(argv);
1601
+ }
1278
1602
  process.exit(0);
1279
1603
  } catch (err) {
1280
1604
  if (err instanceof NoAvailableParticipantsError) {
1281
1605
  console.log(err.message);
1282
1606
  process.exit(0);
1283
1607
  }
1284
- console.error("Benchmark failed:", err instanceof Error ? err.message : err);
1608
+ console.error("Benchmark failed:", String(err));
1285
1609
  process.exit(1);
1286
1610
  }
1287
1611
  }
1288
1612
 
1289
1613
  // src/index.ts
1290
- var BENCHSDK_RUNNER_VERSION = "0.3.0";
1614
+ import { resolveAuth as resolveAuth3, createApiClient, AuthError } from "@benchsdk/cli";
1615
+ import {
1616
+ runWorker as runWorker2,
1617
+ BenchmarkReporter as BenchmarkReporter2,
1618
+ claimBenchmarkReporter,
1619
+ createSystemMetricsCollector as createSystemMetricsCollector2,
1620
+ filterParticipantsByEnv as filterParticipantsByEnv3,
1621
+ selectParticipants as selectParticipants3
1622
+ } from "@benchsdk/worker";
1623
+ import { BenchmarkApiError as BenchmarkApiError2, createBenchmarkClient as createBenchmarkClient3 } from "@benchsdk/api";
1624
+ var BENCHSDK_RUNNER_VERSION = "0.5.2";
1291
1625
  export {
1626
+ AuthError,
1292
1627
  BENCHSDK_RUNNER_VERSION,
1628
+ BenchmarkApiError2 as BenchmarkApiError,
1629
+ BenchmarkConfigError,
1630
+ BenchmarkReporter2 as BenchmarkReporter,
1293
1631
  NoAvailableParticipantsError,
1294
1632
  ScoringSpecError,
1295
1633
  TaskError,
1634
+ claimBenchmarkReporter,
1635
+ createApiClient,
1636
+ createBenchmarkClient3 as createBenchmarkClient,
1637
+ createSystemMetricsCollector2 as createSystemMetricsCollector,
1296
1638
  defineBenchmarkConfig,
1639
+ defineOnComplete,
1297
1640
  defineTask,
1641
+ filterParticipantsByEnv3 as filterParticipantsByEnv,
1298
1642
  higherIsBetter,
1299
1643
  lowerIsBetter,
1300
1644
  mergeConfig,
1301
1645
  parseCliArgs,
1646
+ resolveAuth3 as resolveAuth,
1302
1647
  run,
1303
1648
  runBenchmark,
1304
1649
  runBenchmarkFile,
1650
+ runBenchmarkWorker,
1651
+ runWorker2 as runWorker,
1305
1652
  score,
1306
1653
  scoringConfigToSpec,
1654
+ selectParticipants3 as selectParticipants,
1655
+ validateBenchmarkConfig,
1307
1656
  validateScoringSpec
1308
1657
  };
1309
1658
  //# sourceMappingURL=index.js.map