@benchsdk/runner 0.2.0 → 0.3.0

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,"sources":["../src/index.ts","../src/bench-config.ts","../src/no-available-participants.ts","../src/runner.ts","../src/scoring.ts","../src/log-buffer.ts","../src/cli.ts"],"sourcesContent":["export { defineBenchmarkConfig, defineTask, TaskError } from './bench-config.js';\nexport type {\n BenchmarkConfig,\n BenchmarkTask,\n TaskContext,\n TaskResult,\n TaskStepOptions,\n Phase,\n GroupBy,\n ParticipantRecords,\n ResolvedRunConfig,\n BenchmarkRunOutcome,\n} from './bench-config.js';\nexport { NoAvailableParticipantsError } from './no-available-participants.js';\nexport { runBenchmark, parseCliArgs, mergeConfig } from './runner.js';\nexport type { CliArgs } from './runner.js';\nexport { run, runBenchmarkFile } from './cli.js';\nexport { score, lowerIsBetter, higherIsBetter } from './scoring.js';\nexport type { ScoringSpec, MetricScoring, BenchmarkScoreResult } from './scoring.js';\n","/**\n * A `*.bench.ts` file is the composition of a **config** and a **task**:\n *\n * export const config = defineBenchmarkConfig({ benchmarkSlug, participants, ... });\n * export const task = defineTask(async (ctx) => { await ctx.step('work', () => ...); });\n *\n * `defineBenchmarkConfig` holds the orchestration knobs (including the\n * participants and an optional `onComplete` hook); `defineTask` holds the\n * workload. The `bench run <file>` binary imports the module, reads those two\n * exports, and drives the run. There is no \"mode\": all orchestration shapes\n * emerge from the knobs.\n *\n * iterations total tasks to run (default 1)\n * concurrency max tasks in flight at once — 1 = sequential, N = burst (default 1)\n * staggerDelayMs delay each task's start by taskIndex * staggerDelayMs (default 0)\n *\n * Common shapes:\n * sequential { iterations: N, concurrency: 1 }\n * burst { iterations: N, concurrency: N }\n * staggered { iterations: N, concurrency: N, staggerDelayMs: 200 }\n *\n * A benchmark can name these variants up front via `shapes`, so one file backs\n * several platform benchmarks (`bench run <file> --shape burst`) without\n * restating each one's slug/name in scripts and CI.\n *\n * A task is comprised of steps, declared via `ctx.step` inside a task function\n * — it supports closures, conditionals and try/finally, so values (a created\n * sandbox, say) flow naturally between steps. A task that declares no steps is\n * recorded as a single implicit `task` step. Measurements reach the platform\n * via `ctx.measure(...)`; step return values are control flow and never\n * recorded.\n */\nimport type {\n BaseParticipant,\n DefineStepOptions,\n JsonObject,\n TaskResultRecord,\n TaskStepRecord,\n} from '@benchsdk/client';\nimport type { HigherIsBetter, LowerIsBetter, ScoringSpec } from './scoring.js';\n\n/** How tasks are ordered across participants. */\nexport type GroupBy = 'participant' | 'round';\n\n/**\n * A named variant of a benchmark, selected with `--shape <name>`. A shape\n * carries only the parts that make it a distinct *benchmark* — its platform\n * identity plus any stable distinguishing knob (e.g. staggered's delay). The\n * scale knobs that vary per environment (`--iterations`, `--concurrency`) stay\n * on the invocation, so a shape never sets a value only to have the CLI\n * override it.\n */\nexport interface BenchmarkShape {\n /** Platform slug this shape reports under (e.g. 'sandbox-tti'). */\n slug: string;\n /** Display name shown on the platform; defaults to the slug. */\n name?: string;\n /** Default stagger delay (ms) for this shape; overridable with `--stagger-delay-ms`. */\n staggerDelayMs?: number;\n}\n\n/**\n * What a task returns: whatever it measured itself. This replaces the\n * assumption that the framework owns all timing. A plain data payload is\n * written explicitly as `{ data: {...} }`.\n */\nexport interface TaskResult {\n /** Free-form domain payload attached to the record (tokens, receipts, ...). */\n data?: JsonObject;\n /**\n * Pre-measured steps the task timed itself (e.g. socket phases).\n * Only honored in `groupBy: 'round'` runs, where the runner builds records\n * manually. In `groupBy: 'participant'` runs the platform worker\n * (`client.runWorker`) owns steps, so `steps` and `latencyMs` are ignored.\n */\n steps?: TaskStepRecord[];\n /** Task-owned overall latency; overrides framework wall-clock (round mode only). */\n latencyMs?: number;\n}\n\n/** Options for a single `ctx.step` invocation. */\nexport interface TaskStepOptions extends Omit<DefineStepOptions, 'concurrency' | 'stepConcurrency'> {\n /** Per-iteration timeout in milliseconds. If an invocation exceeds this, it is aborted and a `step_timeout` TaskError is thrown. */\n timeoutMs?: number;\n /** Number of times to invoke `fn` in parallel. Defaults to 1. When greater than 1, the step returns an array of results. */\n concurrency?: number;\n}\n\n/**\n * Throw this from a task to record a failure while preserving domain data and\n * any pre-measured steps (a plain thrown Error loses them).\n */\nexport class TaskError extends Error {\n readonly code?: string;\n readonly data?: JsonObject;\n readonly steps?: TaskStepRecord[];\n constructor(message: string, opts?: { code?: string; data?: JsonObject; steps?: TaskStepRecord[] }) {\n super(message);\n this.name = 'TaskError';\n this.code = opts?.code;\n this.data = opts?.data;\n this.steps = opts?.steps;\n }\n}\n\n/** Context handed to a benchmark `task` for a single iteration. */\nexport interface TaskContext<T extends BaseParticipant = BaseParticipant> {\n /** The participant this task is running for. */\n participant: T;\n /** Zero-based global task ordinal (matches the platform record's taskIndex). */\n taskIndex: number;\n /** Current phase name, when the benchmark declares `phases`. */\n phase?: string;\n /**\n * Runs `fn` as a named platform step. Mirrors `@benchsdk/client`'s\n * `RunWorkerContext.step`; supports closures and try/finally. A `concurrency`\n * greater than 1 invokes `fn` that many times in parallel and returns an array.\n * `timeoutMs` aborts any invocation that exceeds it with a `step_timeout` TaskError.\n */\n step<R, C extends number = 1>(\n name: string,\n fn: () => Promise<R> | R,\n options?: TaskStepOptions & { concurrency?: C },\n ): Promise<C extends 1 ? R : R[]>;\n /**\n * Attaches a JSON measurement to the platform. Inside a `step` it lands on\n * that step's data; at task top-level it lands on the task record's data.\n */\n measure(data: JsonObject): void;\n /** Appends a line to the worker log, uploaded as an artifact when the worker finishes. */\n log(message: string, meta?: JsonObject): void;\n}\n\nexport type BenchmarkTask<T extends BaseParticipant = BaseParticipant> = (\n ctx: TaskContext<T>,\n) => Promise<TaskResult | void> | TaskResult | void;\n\n/**\n * A named run segment with its own iteration count. Phases run in order; each\n * record is tagged with the phase name via `data.phase`, and `ctx.phase` lets\n * the task branch on identity instead of index arithmetic.\n */\nexport interface Phase {\n /** Phase name, tagged onto every record produced in this phase. */\n name: string;\n /** Iterations to run in this phase. */\n iterations: number;\n}\n\n/** One participant's collected task records from a run. */\nexport interface ParticipantRecords {\n participant: string;\n records: TaskResultRecord[];\n}\n\n/** The orchestration knobs a run actually used, after CLI overrides. */\nexport interface ResolvedRunConfig {\n iterations: number;\n concurrency: number;\n staggerDelayMs: number;\n groupBy: GroupBy;\n providers?: string[];\n}\n\n/**\n * Result of a benchmark run, passed to `config.onComplete`. Exposes the raw\n * per-participant records so completion hooks can write legacy local results.\n */\nexport interface BenchmarkRunOutcome {\n runId: string;\n /** Link to this run on the platform dashboard. */\n dashboardUrl: string;\n participants: ParticipantRecords[];\n config: ResolvedRunConfig;\n}\n\n/**\n * Orchestration config for a benchmark. Holds identity, the knobs, the\n * participants, and the optional completion hook — the workload lives in a\n * separate `defineTask`. `bench run <file>` reads the `config` and `task`\n * exports from the module and drives the run.\n */\nexport interface BenchmarkConfig<T extends BaseParticipant = BaseParticipant> {\n /**\n * Stable platform slug for this benchmark (e.g. 'sandbox-tti-local').\n * Selectable per run with `--shape` (or overridable with `--benchmark`), so\n * one entrypoint can report under several benchmarks.\n */\n benchmarkSlug: string;\n /** Human-readable name shown on the platform. Overridable with `--name`. */\n benchmarkName: string;\n /**\n * Named variants of this benchmark, selected with `--shape <name>`. Each\n * shape swaps in its own platform identity (and optional stable knob) while\n * reusing the same task and participants, so one bench file can back several\n * platform benchmarks without duplicating the slug/name triple across\n * package scripts and CI.\n */\n shapes?: Record<string, BenchmarkShape>;\n /**\n * Total tasks to run per participant. Default: 1. Mutually exclusive with\n * `phases` — when `phases` is set, total iterations = sum of phase iterations.\n */\n iterations?: number;\n /**\n * Named run segments (e.g. cold/warm). Runs in order; each record is tagged\n * with the phase name via `data.phase`. Mutually exclusive with `iterations`.\n */\n phases?: Phase[];\n /** Max tasks in flight at once. 1 = sequential, N = burst. Default: 1. */\n concurrency?: number;\n /** Delay each task's start by `taskIndex * staggerDelayMs`. Default: 0. */\n staggerDelayMs?: number;\n /**\n * Task ordering across participants. Default: 'participant' (run each\n * participant's tasks to completion, then the next). 'round' takes turns:\n * every participant runs its Nth task before anyone runs their (N+1)th, so\n * all participants' Nth tasks happen back-to-back under the same conditions.\n */\n groupBy?: GroupBy;\n /**\n * Default participant names to run when `--provider` is not passed. Omit to\n * run all env-available participants. `--provider` always overrides this.\n */\n defaultProviders?: string[];\n /** The participants this benchmark can run against. `--provider` selects a subset by name. */\n participants: T[];\n /**\n * Run-level scoring hook, called once with `lowerIsBetter` and `higherIsBetter`\n * primitives after the outcome is assembled but before `onComplete`. Use it to\n * define how the run should be scored and reported to the platform.\n */\n onScore?: (lowerIsBetter: LowerIsBetter, higherIsBetter: HigherIsBetter) => ScoringSpec | Promise<ScoringSpec>;\n /**\n * Run-level completion hook, called once with the full outcome after every\n * participant finishes. Use it for aggregate output (legacy JSON/SVG\n * writers). This is the run-level counterpart to per-step `ctx.measure`.\n */\n onComplete?: (outcome: BenchmarkRunOutcome) => void | Promise<void>;\n}\n\nfunction assertPositiveInt(value: number | undefined, field: string): void {\n if (value === undefined) return;\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`${field} must be an integer >= 1 (got ${value})`);\n }\n}\n\n/** Validates `config` at file-evaluation time so mistakes surface immediately. */\nexport function defineBenchmarkConfig<T extends BaseParticipant = BaseParticipant>(\n config: BenchmarkConfig<T>,\n): BenchmarkConfig<T> {\n if (!config.benchmarkSlug || typeof config.benchmarkSlug !== 'string') {\n throw new Error('benchmarkSlug is required');\n }\n if (!config.benchmarkName || typeof config.benchmarkName !== 'string') {\n throw new Error('benchmarkName is required');\n }\n if (config.phases !== undefined) {\n if (config.iterations !== undefined) {\n throw new Error('phases and iterations are mutually exclusive');\n }\n if (!Array.isArray(config.phases) || config.phases.length === 0) {\n throw new Error('phases must be a non-empty array');\n }\n const seen = new Set<string>();\n for (const phase of config.phases) {\n if (!phase.name || typeof phase.name !== 'string') {\n throw new Error('each phase requires a non-empty name');\n }\n if (seen.has(phase.name)) {\n throw new Error(`duplicate phase name: ${phase.name}`);\n }\n seen.add(phase.name);\n assertPositiveInt(phase.iterations, `phase '${phase.name}' iterations`);\n }\n }\n assertPositiveInt(config.iterations, 'iterations');\n assertPositiveInt(config.concurrency, 'concurrency');\n if (config.staggerDelayMs !== undefined && (!Number.isFinite(config.staggerDelayMs) || config.staggerDelayMs < 0)) {\n throw new Error(`staggerDelayMs must be a number >= 0 (got ${config.staggerDelayMs})`);\n }\n if (config.groupBy !== undefined && config.groupBy !== 'participant' && config.groupBy !== 'round') {\n throw new Error(`groupBy must be 'participant' or 'round' (got ${config.groupBy})`);\n }\n if (config.shapes !== undefined) {\n for (const [shapeName, shape] of Object.entries(config.shapes)) {\n if (!shape.slug || !/^[a-z0-9][a-z0-9-]*$/.test(shape.slug)) {\n throw new Error(`shape '${shapeName}' needs a lowercase slug (got ${JSON.stringify(shape.slug)})`);\n }\n if (shape.name !== undefined && (typeof shape.name !== 'string' || shape.name.trim() === '')) {\n throw new Error(`shape '${shapeName}' name must be a non-empty string`);\n }\n if (shape.staggerDelayMs !== undefined && (!Number.isFinite(shape.staggerDelayMs) || shape.staggerDelayMs < 0)) {\n throw new Error(`shape '${shapeName}' staggerDelayMs must be a number >= 0 (got ${shape.staggerDelayMs})`);\n }\n }\n }\n return config;\n}\n\n/**\n * Declares the workload for a benchmark: a function invoked once per iteration.\n * Steps are named via `ctx.step`, which supports closures and try/finally so\n * values flow naturally between steps.\n *\n * export const task = defineTask(async (ctx) => {\n * const sandbox = await ctx.step('create', () => provider.create());\n * try { await ctx.step('exec', () => sandbox.run('node -v')); }\n * finally { await ctx.step('destroy', () => sandbox.destroy()); }\n * });\n */\nexport function defineTask<T extends BaseParticipant = BaseParticipant>(\n task: BenchmarkTask<T>,\n): BenchmarkTask<T> {\n if (typeof task !== 'function') {\n throw new Error('defineTask requires a task function.');\n }\n return task;\n}\n","/**\n * Thrown when every selected participant was env-gated out, i.e. none of their\n * `requiredEnvVars` are set. This is a \"nothing to do\" outcome rather than a\n * failure — a benchmark job for a provider whose credentials aren't provisioned\n * should skip, not go red — so callers are expected to exit 0 on it.\n */\nexport class NoAvailableParticipantsError extends Error {\n readonly skipped: { name: string; missing: string[] }[];\n\n constructor(skipped: { name: string; missing: string[] }[]) {\n super(\n `No participants have their required env vars set — nothing to run${\n skipped.length > 0 ? ` (skipped: ${skipped.map((s) => s.name).join(', ')})` : ''\n }.`,\n );\n this.name = 'NoAvailableParticipantsError';\n this.skipped = skipped;\n }\n}\n","/**\n * CLI runner for `defineBenchmark` configs. Owns all platform orchestration\n * (upsert benchmark, create run, plan + drive workers per participant) so a\n * `*.bench.ts` file only has to declare its config and task. The orchestration\n * knobs (iterations / concurrency / staggerDelayMs / groupBy) can be overridden\n * per-invocation via CLI flags.\n *\n * Two execution orderings, chosen by `groupBy`:\n * 'participant' (default) — each participant's tasks run to completion via\n * `client.runWorker` (with its pooled concurrency + heartbeat reporting)\n * before the next participant starts.\n * 'round' — participants take turns: every participant runs its Nth task\n * before anyone starts their (N+1)th, so all Nth tasks happen back-to-back\n * under the same conditions. Driven manually via one `BenchmarkReporter`\n * per participant.\n */\nimport { execSync } from 'node:child_process';\nimport os from 'node:os';\nimport {\n BenchmarkReporter,\n createBenchmarkClient,\n filterParticipantsByEnv,\n selectParticipants,\n} from '@benchsdk/client';\nimport { NoAvailableParticipantsError } from './no-available-participants.js';\nimport { higherIsBetter, lowerIsBetter, score } from './scoring.js';\nimport type {\n BaseParticipant,\n BenchmarkClient,\n DefineStepOptions,\n JsonObject,\n RunWorkerContext,\n TaskResultRecord,\n TaskStepRecord,\n} from '@benchsdk/client';\nimport { TaskError } from './bench-config.js';\nimport type {\n BenchmarkConfig,\n BenchmarkRunOutcome,\n BenchmarkShape,\n BenchmarkTask,\n GroupBy,\n ParticipantRecords,\n ResolvedRunConfig,\n TaskContext,\n TaskResult,\n TaskStepOptions,\n} from './bench-config.js';\nimport { LogBuffer } from './log-buffer.js';\n\nexport interface CliArgs {\n /** Which platform benchmark to report as (`--benchmark`, aka the benchmark slug). */\n benchmark?: string;\n name?: string;\n /** Named variant from the bench file's `shapes` (`--shape`), swapping in its identity. */\n shape?: string;\n /**\n * Idempotency key (`--run-key`): sibling processes passing the same key share\n * one run (get-or-created), instead of each opening its own.\n */\n runKey?: string;\n iterations?: number;\n concurrency?: number;\n staggerDelayMs?: number;\n groupBy?: GroupBy;\n /** Participant names from `--provider a,b` (repeatable). */\n providers?: string[];\n /** When true, run locally and do not ingest/report to the platform. */\n noIngest?: boolean;\n}\n\n// Matches @benchsdk/client's DEFAULT_BASE_URL origin. `resolvePlatform()`\n// appends `/api/v1`. Override for local development via BENCHMARKS_PLATFORM_URL.\nconst DEFAULT_PLATFORM_URL = 'https://platform.computesdk.com';\n\nfunction isEnvNoIngest(): boolean {\n const v = process.env.BENCHSDK_NO_INGEST;\n return v === '1' || v?.toLowerCase() === 'true';\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction getErrorCode(error: unknown): string {\n return error instanceof Error && error.name ? error.name : 'ERROR';\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, name: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new TaskError(`Step \"${name}\" timed out after ${ms}ms`, { code: 'step_timeout' })),\n ms,\n );\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\nasync function runStepInvocations<R>(\n name: string,\n fn: () => Promise<R> | R,\n options: TaskStepOptions | undefined,\n): Promise<R | R[]> {\n const requestedConcurrency = options?.concurrency;\n if (requestedConcurrency !== undefined && (!Number.isInteger(requestedConcurrency) || requestedConcurrency < 1)) {\n throw new Error(`step \"${name}\" concurrency must be an integer >= 1 (got ${requestedConcurrency})`);\n }\n const timeoutMs = options?.timeoutMs;\n if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0)) {\n throw new Error(`step \"${name}\" timeoutMs must be a number >= 0 (got ${timeoutMs})`);\n }\n\n const count = requestedConcurrency ?? 1;\n const invocations = Array.from({ length: count }, () => {\n const promise = Promise.resolve().then(() => fn());\n if (timeoutMs === undefined) return promise;\n return withTimeout(promise, timeoutMs, name);\n });\n\n if (count === 1) {\n return invocations[0];\n }\n\n const outcomes = await Promise.allSettled(invocations);\n const results: R[] = [];\n let firstError: unknown;\n for (const outcome of outcomes) {\n if (outcome.status === 'fulfilled') {\n results.push(outcome.value);\n } else if (firstError === undefined) {\n firstError = outcome.reason;\n }\n }\n if (firstError !== undefined) throw firstError;\n return results;\n}\n\nasync function runStepWithClient<R, C extends number = 1>(\n clientStep: RunWorkerContext['step'],\n name: string,\n fn: () => Promise<R> | R,\n options?: TaskStepOptions & { concurrency?: C },\n): Promise<C extends 1 ? R : R[]> {\n const { concurrency: runnerConcurrency, timeoutMs, ...clientOptions } = options ?? {};\n const clientStepOptions: DefineStepOptions = {\n ...clientOptions,\n timeoutMs,\n stepConcurrency: runnerConcurrency,\n };\n const result = await clientStep(name, () => runStepInvocations(name, fn, options), clientStepOptions);\n return result as C extends 1 ? R : R[];\n}\n\n/**\n * Parses the orchestration flags this runner understands, ignoring anything\n * else. Supports both `--flag value` and `--flag=value`; `--provider` accepts\n * a comma-separated list and may be repeated.\n */\nexport function parseCliArgs(argv: string[]): CliArgs {\n const args: CliArgs = {};\n\n const readValue = (raw: string, i: number): { value: string; nextIndex: number } => {\n const eq = raw.indexOf('=');\n if (eq !== -1) return { value: raw.slice(eq + 1), nextIndex: i };\n return { value: argv[i + 1] ?? '', nextIndex: i + 1 };\n };\n\n const intFlag = (raw: string, flag: string): number => {\n if (raw.trim() === '') throw new Error(`${flag} expects a value`);\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 1) throw new Error(`${flag} expects an integer >= 1 (got \"${raw}\")`);\n return n;\n };\n\n const nonNegFlag = (raw: string, flag: string): number => {\n if (raw.trim() === '') throw new Error(`${flag} expects a value`);\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 0) throw new Error(`${flag} expects a number >= 0 (got \"${raw}\")`);\n return n;\n };\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n const name = arg.includes('=') ? arg.slice(0, arg.indexOf('=')) : arg;\n switch (name) {\n // `--slug` is the pre-`--benchmark` spelling, kept working for existing scripts.\n case '--slug':\n case '--benchmark': {\n const { value, nextIndex } = readValue(arg, i);\n if (!/^[a-z0-9][a-z0-9-]*$/.test(value)) {\n throw new Error(`${name} expects a lowercase benchmark slug (got \"${value}\")`);\n }\n args.benchmark = value;\n i = nextIndex;\n break;\n }\n case '--name': {\n const { value, nextIndex } = readValue(arg, i);\n if (value.trim() === '') throw new Error('--name expects a value');\n args.name = value;\n i = nextIndex;\n break;\n }\n case '--shape': {\n const { value, nextIndex } = readValue(arg, i);\n if (value.trim() === '') throw new Error('--shape expects a value');\n args.shape = value;\n i = nextIndex;\n break;\n }\n case '--run-key': {\n const { value, nextIndex } = readValue(arg, i);\n if (value.trim() === '') throw new Error('--run-key expects a value');\n args.runKey = value;\n i = nextIndex;\n break;\n }\n case '--iterations': {\n const { value, nextIndex } = readValue(arg, i);\n args.iterations = intFlag(value, '--iterations');\n i = nextIndex;\n break;\n }\n case '--concurrency': {\n const { value, nextIndex } = readValue(arg, i);\n args.concurrency = intFlag(value, '--concurrency');\n i = nextIndex;\n break;\n }\n case '--stagger-delay-ms': {\n const { value, nextIndex } = readValue(arg, i);\n args.staggerDelayMs = nonNegFlag(value, '--stagger-delay-ms');\n i = nextIndex;\n break;\n }\n case '--group-by': {\n const { value, nextIndex } = readValue(arg, i);\n if (value !== 'participant' && value !== 'round') {\n throw new Error(`--group-by expects 'participant' or 'round' (got \"${value}\")`);\n }\n args.groupBy = value;\n i = nextIndex;\n break;\n }\n case '--provider': {\n const { value, nextIndex } = readValue(arg, i);\n const names = value.split(',').map((s) => s.trim()).filter(Boolean);\n args.providers = [...(args.providers ?? []), ...names];\n i = nextIndex;\n break;\n }\n case '--no-ingest':\n case '--dry-run':\n args.noIngest = true;\n break;\n default:\n break;\n }\n }\n\n if (!args.noIngest && isEnvNoIngest()) {\n args.noIngest = true;\n }\n return args;\n}\n\n/** Merges CLI overrides over config defaults, filling in knob fallbacks. */\nexport function mergeConfig<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n args: CliArgs,\n): ResolvedRunConfig {\n const phaseTotal = config.phases?.reduce((sum, p) => sum + p.iterations, 0);\n if (phaseTotal !== undefined && args.iterations !== undefined) {\n console.warn('--iterations is ignored because this benchmark declares phases.');\n }\n const resolved: ResolvedRunConfig = {\n iterations: phaseTotal ?? args.iterations ?? config.iterations ?? 1,\n concurrency: args.concurrency ?? config.concurrency ?? 1,\n staggerDelayMs: args.staggerDelayMs ?? config.staggerDelayMs ?? 0,\n groupBy: args.groupBy ?? config.groupBy ?? 'participant',\n providers: args.providers ?? config.defaultProviders,\n };\n if (!Number.isInteger(resolved.iterations) || resolved.iterations < 1) {\n throw new Error(`iterations must be an integer >= 1 (got ${resolved.iterations})`);\n }\n if (!Number.isInteger(resolved.concurrency) || resolved.concurrency < 1) {\n throw new Error(`concurrency must be an integer >= 1 (got ${resolved.concurrency})`);\n }\n return resolved;\n}\n\n/** One scheduled task slot: which task to run and (optionally) under which phase. */\ninterface Slot<T extends BaseParticipant = BaseParticipant> {\n phase?: string;\n task: BenchmarkTask<T>;\n}\n\n/**\n * Flattens a config into an ordered list of task slots. With `phases`, each\n * phase contributes `iterations` slots tagged with its name (framework owns\n * the phase boundary — no index arithmetic in the task). Without phases, the\n * task is repeated `iterations` times.\n */\nfunction buildSchedule<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n iterations: number,\n task: BenchmarkTask<T>,\n): Slot<T>[] {\n if (config.phases?.length) {\n return config.phases.flatMap((phase) =>\n Array.from({ length: phase.iterations }, () => ({ phase: phase.name, task })),\n );\n }\n return Array.from({ length: iterations }, () => ({ phase: undefined, task }));\n}\n\ntype OnResult = (record: TaskResultRecord, meta: { iterations: number; participant: string }) => void;\n\nfunction defaultOnResult(record: TaskResultRecord, meta: { iterations: number; participant: string }): void {\n const n = record.taskIndex + 1;\n if (record.status === 'success') {\n const data = record.data && Object.keys(record.data).length > 0 ? ` ${JSON.stringify(record.data)}` : '';\n console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: success${data}`);\n } else {\n console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: FAILED — ${record.errorCode ?? 'unknown error'}`);\n }\n}\n\nfunction resolvePlatform(): { baseUrl: string; apiKey: string } {\n const root = (process.env.BENCHMARKS_PLATFORM_URL || DEFAULT_PLATFORM_URL).replace(/\\/+$/, '');\n const apiKey = process.env.BENCHMARKS_PLATFORM_API_KEY;\n if (!apiKey) {\n throw new Error(\n 'BENCHMARKS_PLATFORM_API_KEY is required. Create an org-scoped API key ' +\n 'in your organization settings on the platform and set it in your .env.'\n );\n }\n return {\n baseUrl: `${root}/api/v1`,\n apiKey,\n };\n}\n\n/**\n * Resolves `--shape <name>` against the config's declared `shapes`. Throws with\n * the known names if the shape is unknown, so a typo fails loudly instead of\n * silently running the base benchmark.\n */\nfunction resolveShape<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n shapeName: string | undefined,\n): BenchmarkShape | undefined {\n if (!shapeName) return undefined;\n const shape = config.shapes?.[shapeName];\n if (!shape) {\n const known = Object.keys(config.shapes ?? {});\n throw new Error(\n known.length > 0\n ? `Unknown --shape \"${shapeName}\". Known shapes: ${known.join(', ')}.`\n : `Unknown --shape \"${shapeName}\": this benchmark declares no shapes.`,\n );\n }\n return shape;\n}\n\n/**\n * Swaps a shape's identity (and its stable knob) into the config. Only the\n * parts that make it a distinct benchmark move here; scale knobs stay on the\n * CLI, so `mergeConfig` still lets `--concurrency`/`--iterations` win.\n */\nfunction applyShape<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n shape: BenchmarkShape | undefined,\n): BenchmarkConfig<T> {\n if (!shape) return config;\n return {\n ...config,\n benchmarkSlug: shape.slug,\n benchmarkName: shape.name ?? shape.slug,\n ...(shape.staggerDelayMs !== undefined ? { staggerDelayMs: shape.staggerDelayMs } : {}),\n };\n}\n\n/** Applies the `--benchmark`/`--name` overrides, so one entrypoint can report under several benchmarks. */\nfunction applyIdentityOverrides<T extends BaseParticipant>(\n fileConfig: BenchmarkConfig<T>,\n args: CliArgs,\n): BenchmarkConfig<T> {\n return {\n ...fileConfig,\n ...(args.benchmark ? { benchmarkSlug: args.benchmark } : {}),\n ...(args.name ? { benchmarkName: args.name } : {}),\n };\n}\n\nfunction dashboardUrlFor(baseUrl: string, organizationSlug: string, benchmarkSlug: string, runId: string): string {\n return `${baseUrl.replace(/\\/api\\/v1\\/?$/, '')}/${organizationSlug}/benchmarks/${benchmarkSlug}/runs/${runId}`;\n}\n\n/** The participants a run covers: `--provider` selection, minus any whose env vars are unset. */\nfunction resolveParticipants<T extends BaseParticipant>(config: BenchmarkConfig<T>, resolved: ResolvedRunConfig): T[] {\n const { available, skipped } = filterParticipantsByEnv(selectParticipants(config.participants, resolved.providers));\n for (const s of skipped) {\n console.log(`Skipping ${s.name}: missing ${s.missing.join(', ')}`);\n }\n if (available.length === 0) throw new NoAvailableParticipantsError(skipped);\n return available;\n}\n\n/**\n * Runs `config`'s `task` against its participants. Selects participants by\n * `--provider` (if given), env-gates them, then drives them per the resolved\n * `groupBy`. `--shape` swaps in a declared variant's identity; `--benchmark`/\n * `--name` retarget the run at a different platform benchmark, so one entrypoint\n * can report under several slugs. With `--run-key`, sibling processes (e.g. one\n * CI job per provider) get-or-create one shared run and each registers only its\n * own participants.\n */\nexport async function runBenchmark<T extends BaseParticipant>(\n fileConfig: BenchmarkConfig<T>,\n task: BenchmarkTask<T>,\n argv: string[] = [],\n): Promise<BenchmarkRunOutcome> {\n const args = parseCliArgs(argv);\n const noIngest = args.noIngest ?? isEnvNoIngest();\n const shaped = applyShape(fileConfig, resolveShape(fileConfig, args.shape));\n const config = applyIdentityOverrides(shaped, args);\n const resolved = mergeConfig(config, args);\n const available = resolveParticipants(config, resolved);\n\n let baseUrl = '';\n let apiKey = '';\n let client: BenchmarkClient | null = null;\n if (!noIngest) {\n ({ baseUrl, apiKey } = resolvePlatform());\n client = createBenchmarkClient({ baseUrl, apiKey });\n }\n\n const schedule = buildSchedule(config, resolved.iterations, task);\n const totalTasks = schedule.length;\n\n const concurrencyLabel = resolved.groupBy === 'round' ? 'n/a (round mode)' : String(resolved.concurrency);\n console.log(`${config.benchmarkName} (self-contained)`);\n console.log(`Date: ${new Date().toISOString()}`);\n if (noIngest) {\n console.log('Dry run: no platform ingest or reporting.\\n');\n }\n console.log(\n `Knobs: iterations=${totalTasks}, concurrency=${concurrencyLabel}, ` +\n `staggerDelayMs=${resolved.staggerDelayMs}, groupBy=${resolved.groupBy}\\n`,\n );\n\n // Declaratively materialize the benchmark from the file/shape identity, which\n // is authoritative (its name lives in the file). A bare `--benchmark X` only\n // *retargets* reporting at a benchmark this file doesn't name, so we don't\n // upsert it — that would rename it to the file's own name.\n const identityIsOurs =\n args.shape !== undefined ||\n args.name !== undefined ||\n !args.benchmark ||\n args.benchmark === fileConfig.benchmarkSlug;\n\n let runId: string;\n let dashboardUrl: string;\n if (noIngest) {\n runId = 'no-ingest';\n dashboardUrl = '';\n } else {\n if (identityIsOurs) {\n await client!.upsertBenchmark(config.benchmarkSlug, {\n name: config.benchmarkName,\n });\n }\n\n if (args.runKey) {\n // Shared run: get-or-created by key, so sibling processes (one per provider)\n // converge on one run. Opened participant-sized — register only the\n // providers this process runs and let each sibling register its own, so the\n // run lists exactly who's benchmarked and each brings its own task count.\n const { run, organizationSlug } = await client!.createRun(config.benchmarkSlug, {\n runKey: args.runKey,\n });\n runId = run.id;\n dashboardUrl = dashboardUrlFor(baseUrl, organizationSlug, config.benchmarkSlug, run.id);\n for (const participant of available) {\n await client!.upsertParticipant(config.benchmarkSlug, runId, participant.name, { totalTasks });\n }\n console.log(`Shared run (key \"${args.runKey}\"): ${run.name} (${runId})`);\n console.log(`View at: ${dashboardUrl}\\n`);\n } else {\n const { run, organizationSlug } = await client!.createRun(config.benchmarkSlug, {\n totalTasks,\n workerCount: 1,\n participants: available.map((p) => p.name),\n });\n runId = run.id;\n dashboardUrl = dashboardUrlFor(baseUrl, organizationSlug, config.benchmarkSlug, run.id);\n console.log(`Run created: ${run.name} (${runId})`);\n console.log(`View at: ${dashboardUrl}\\n`);\n }\n }\n\n const onResult = defaultOnResult;\n\n let participantRecords: ParticipantRecords[];\n if (resolved.groupBy === 'round') {\n participantRecords = await runGroupedByRound(config, schedule, available, resolved, client, runId, baseUrl, apiKey, onResult, noIngest);\n } else {\n participantRecords = await runGroupedByParticipant(config, schedule, available, resolved, client, runId, onResult);\n }\n\n console.log(`All done. ${noIngest ? 'No platform run created.' : `View at: ${dashboardUrl}`}`);\n const outcome: BenchmarkRunOutcome = {\n runId,\n dashboardUrl,\n participants: participantRecords,\n config: resolved,\n };\n if (client && config.onScore) {\n try {\n const spec = await config.onScore(lowerIsBetter, higherIsBetter);\n const scored = score(outcome, spec);\n const run = {\n gitSha: process.env.GITHUB_SHA ?? getGitSha(),\n gitRef: process.env.GITHUB_REF_NAME ?? process.env.GITHUB_REF ?? getGitRef(),\n triggeredBy: process.env.GITHUB_EVENT_NAME ?? 'manual',\n nodeVersion: process.version,\n platform: os.platform(),\n arch: os.arch(),\n };\n await client.submitRunSummary(config.benchmarkSlug, runId, { run, results: scored });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.warn(`[benchsdk-runner] failed to submit run summary: ${message}`);\n }\n }\n if (config.onComplete) await config.onComplete(outcome);\n return outcome;\n}\n\nfunction getGitSha(): string | undefined {\n if (process.env.GITHUB_SHA) return process.env.GITHUB_SHA;\n try {\n return execSync('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();\n } catch {\n return undefined;\n }\n}\n\nfunction getGitRef(): string | undefined {\n if (process.env.GITHUB_REF_NAME) return process.env.GITHUB_REF_NAME;\n if (process.env.GITHUB_REF) return process.env.GITHUB_REF;\n try {\n return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();\n } catch {\n return undefined;\n }\n}\n\n/**\n * 'participant' ordering: one `client.runWorker` per participant, in turn.\n * `staggerDelayMs` here launches task N at `workerStart + N * staggerDelayMs`\n * (vs. round mode's fixed delay between rounds — intentionally different).\n * `TaskResult.steps`/`latencyMs` are ignored in this path: the platform\n * worker owns step timing and latency.\n */\nasync function runGroupedByParticipant<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n schedule: Slot<T>[],\n available: T[],\n resolved: ResolvedRunConfig,\n client: BenchmarkClient | null,\n runId: string,\n onResult: OnResult,\n): Promise<ParticipantRecords[]> {\n const participantRecords: ParticipantRecords[] = [];\n for (const participant of available) {\n console.log(`${'='.repeat(70)}`);\n console.log(` Participant: ${participant.name}`);\n console.log('='.repeat(70));\n\n // When running without platform ingest, execute the schedule locally.\n if (!client) {\n const records: TaskResultRecord[] = [];\n let rampStartMs: number | undefined;\n let nextIndex = 0;\n const logBuffer = new LogBuffer();\n\n const runSlot = async (scheduleIndex: number) => {\n if (resolved.staggerDelayMs > 0) {\n rampStartMs ??= Date.now();\n const waitMs = rampStartMs + scheduleIndex * resolved.staggerDelayMs - Date.now();\n if (waitMs > 0) await sleep(waitMs);\n }\n const slot = schedule[scheduleIndex];\n const record = await runTaskRecord(slot.task, participant, scheduleIndex, scheduleIndex, slot.phase, logBuffer);\n onResult(record, { iterations: schedule.length, participant: participant.name });\n records.push(record);\n };\n\n const worker = async () => {\n while (nextIndex < schedule.length) {\n const index = nextIndex++;\n await runSlot(index);\n }\n };\n\n await Promise.all(Array.from({ length: resolved.concurrency }, () => worker()));\n records.sort((a, b) => a.taskIndex - b.taskIndex);\n\n const ok = records.filter((r) => r.status === 'success').length;\n console.log(` Done: ${ok}/${records.length} succeeded.\\n`);\n participantRecords.push({ participant: participant.name, records });\n continue;\n }\n\n // Anchors the ramp to the worker's start, so a pool narrower than the task\n // count can't inflate launch offsets: a task whose slot frees after its\n // scheduled launch time starts immediately instead of sleeping index*delay.\n let rampStartMs: number | undefined;\n await client.planWorkers(config.benchmarkSlug, runId, participant.name);\n\n const result = await client.runWorker({\n benchmarkSlug: config.benchmarkSlug,\n runId: runId,\n participantSlug: participant.name,\n concurrency: resolved.concurrency,\n task: async (ctx: RunWorkerContext) => {\n // `ctx.taskIndex` is the platform's global index; the schedule is\n // indexed from the worker's own task range start.\n const scheduleIndex = ctx.taskIndex - ctx.assignment.taskRange.start;\n if (resolved.staggerDelayMs > 0) {\n rampStartMs ??= Date.now();\n const waitMs = rampStartMs + scheduleIndex * resolved.staggerDelayMs - Date.now();\n if (waitMs > 0) await sleep(waitMs);\n }\n const slot = schedule[scheduleIndex];\n // The client owns step timing, `measure` attribution, and worker-log\n // upload; the runner just threads them onto the task context. The runner\n // wraps `ctx.step` so per-step `timeoutMs` and `concurrency` work in\n // participant mode as well.\n const taskResult = await slot.task({\n participant,\n taskIndex: scheduleIndex,\n phase: slot.phase,\n step: (name, fn, options) => runStepWithClient(ctx.step, name, fn, options),\n measure: ctx.measure,\n log: ctx.log,\n });\n if (slot.phase) ctx.measure({ phase: slot.phase });\n return taskResult?.data;\n },\n onResult: (record) => onResult(record, { iterations: schedule.length, participant: participant.name }),\n });\n\n if (!result.assignment) {\n console.error(` No pending worker to claim for run ${runId} — it may already be fully claimed.`);\n participantRecords.push({ participant: participant.name, records: result.records ?? [] });\n continue;\n }\n\n const ok = result.records.filter((r) => r.status === 'success').length;\n console.log(` Done: ${ok}/${result.records.length} succeeded.\\n`);\n participantRecords.push({ participant: participant.name, records: result.records });\n }\n\n return participantRecords;\n}\n\n/**\n * 'round' ordering: claim one `BenchmarkReporter` per participant up front,\n * then loop rounds, running one task per participant per round and streaming\n * each result to its reporter. Steps are built manually (no `client.runWorker`\n * to own them) via a shim that mirrors the platform's record shape.\n */\nasync function runGroupedByRound<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n schedule: Slot<T>[],\n available: T[],\n resolved: ResolvedRunConfig,\n client: BenchmarkClient | null,\n runId: string,\n baseUrl: string,\n apiKey: string,\n onResult: OnResult,\n noIngest: boolean = false,\n): Promise<ParticipantRecords[]> {\n const reporters = new Map<string, BenchmarkReporter | null>();\n const logBuffers = new Map<string, LogBuffer>();\n const failed = new Map<string, boolean>();\n const recordsByParticipant = new Map<string, TaskResultRecord[]>();\n\n for (const participant of available) {\n logBuffers.set(participant.name, new LogBuffer());\n failed.set(participant.name, false);\n if (noIngest || !client) {\n reporters.set(participant.name, null);\n continue;\n }\n // One worker per participant drives every round sequentially. The platform\n // reads `targetConcurrency` as tasks-per-worker, so it must be the full\n // schedule length — otherwise only one task is planned and every record\n // past the first falls outside the worker's task range.\n await client.planWorkers(config.benchmarkSlug, runId, participant.name, {\n workerCount: 1,\n targetConcurrency: schedule.length,\n });\n let reporter: BenchmarkReporter | null = null;\n try {\n reporter = await BenchmarkReporter.claim({\n baseUrl,\n apiKey,\n benchmarkSlug: config.benchmarkSlug,\n runId: runId,\n participantSlug: participant.name,\n processKind: 'process',\n processKey: process.env.HOSTNAME ?? 'local',\n });\n } catch (error) {\n console.warn(` ${participant.name}: reporter claim failed (${error instanceof Error ? error.message : String(error)}) — running without platform reporting.`);\n }\n if (!reporter) {\n console.warn(` ${participant.name}: could not claim a platform worker — running without platform reporting.`);\n }\n reporters.set(participant.name, reporter);\n }\n\n console.log(`Interleaving ${available.length} participant(s), ${schedule.length} round(s) each.\\n`);\n\n for (let i = 0; i < schedule.length; i++) {\n const slot = schedule[i];\n // Round mode staggers a fixed delay between rounds (vs. participant mode's per-task stagger).\n if (resolved.staggerDelayMs > 0 && i > 0) {\n await sleep(resolved.staggerDelayMs);\n }\n for (const participant of available) {\n const reporter = reporters.get(participant.name) ?? null;\n const logBuffer = logBuffers.get(participant.name)!;\n const record = await runTaskRecord(\n slot.task,\n participant,\n i,\n (reporter?.taskIndexStart ?? 0) + i,\n slot.phase,\n logBuffer,\n );\n if (record.status !== 'success') failed.set(participant.name, true);\n onResult(record, { iterations: schedule.length, participant: participant.name });\n reporter?.recordResult(record);\n if (!recordsByParticipant.has(participant.name)) {\n recordsByParticipant.set(participant.name, []);\n }\n const participantRecords = recordsByParticipant.get(participant.name)!;\n participantRecords.push(record);\n // Round mode drives the worker by hand, so nothing reports progress\n // unless we do: without this the platform shows 0 done for the whole run.\n if (reporter) {\n reporter.setProgress({\n done: participantRecords.length,\n inFlight: 0,\n errors: participantRecords.filter((item) => item.status !== 'success').length,\n total: schedule.length,\n });\n await reporter.heartbeat();\n }\n }\n }\n\n for (const participant of available) {\n const reporter = reporters.get(participant.name) ?? null;\n const logBuffer = logBuffers.get(participant.name)!;\n if (reporter && !logBuffer.isEmpty()) {\n await reporter\n .uploadArtifact({ kind: 'coordinator.log', contentType: 'text/plain', name: 'worker.log', body: logBuffer.toText() })\n .catch(() => {});\n }\n await reporter?.finish(failed.get(participant.name) ?? false);\n console.log(` ${participant.name}: done${failed.get(participant.name) ? ' (with errors)' : ''}.`);\n }\n\n return available.map((p) => ({ participant: p.name, records: recordsByParticipant.get(p.name) ?? [] }));\n}\n\n/** Merges a task's data payload with the current phase tag (if any). */\nfunction mergeData(data: JsonObject | undefined, phase: string | undefined): JsonObject | undefined {\n const merged = { ...(data ?? {}), ...(phase ? { phase } : {}) };\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\n/**\n * Runs one task for the manual 'round' path, building its `TaskResultRecord`.\n * Honors the full `TaskResult` (task-owned data/steps/latency) and `TaskError`\n * (preserves domain data + steps on failure). Framework-timed `ctx.step` calls\n * and task-owned `result.steps` are both recorded.\n */\nasync function runTaskRecord<T extends BaseParticipant>(\n task: BenchmarkTask<T>,\n participant: T,\n scheduleIndex: number,\n taskIndex: number,\n phase: string | undefined,\n logBuffer: LogBuffer,\n): Promise<TaskResultRecord> {\n const startedAtMs = Date.now();\n const record: TaskResultRecord = {\n taskIndex,\n status: 'success',\n startedAt: new Date(startedAtMs).toISOString(),\n };\n const frameworkSteps: TaskStepRecord[] = [];\n const taskMeasures: JsonObject = {};\n // Mirrors the client worker: `measure` lands on the active step (if any),\n // else on task-level measurements folded into `record.data`.\n let activeStep: TaskStepRecord | null = null;\n\n const ctx: TaskContext<T> = {\n participant,\n taskIndex: scheduleIndex,\n phase,\n async step<R, C extends number = 1>(\n name: string,\n fn: () => Promise<R> | R,\n options?: TaskStepOptions & { concurrency?: C },\n ): Promise<C extends 1 ? R : R[]> {\n const stepStartedAtMs = Date.now();\n const stepRecord: TaskStepRecord = {\n name,\n status: 'success',\n startedAt: new Date(stepStartedAtMs).toISOString(),\n completedAt: new Date(stepStartedAtMs).toISOString(),\n latencyMs: 0,\n };\n if (options?.concurrency !== undefined) stepRecord.concurrency = options.concurrency;\n if (options?.timeoutMs !== undefined) stepRecord.timeoutMs = options.timeoutMs;\n const previousStep = activeStep;\n activeStep = stepRecord;\n try {\n const result = await runStepInvocations<R>(name, fn, options);\n logBuffer.step(taskIndex, name, {});\n return result as C extends 1 ? R : R[];\n } catch (error) {\n stepRecord.status = 'error';\n stepRecord.errorCode = error instanceof TaskError ? error.code ?? error.name : getErrorCode(error);\n logBuffer.step(taskIndex, name, { error: error instanceof Error ? error.message : String(error) });\n throw error;\n } finally {\n activeStep = previousStep;\n stepRecord.completedAt = new Date().toISOString();\n stepRecord.latencyMs = Date.now() - stepStartedAtMs;\n frameworkSteps.push(stepRecord);\n }\n },\n measure(data) {\n if (activeStep) {\n activeStep.data = { ...(activeStep.data ?? {}), ...data };\n } else {\n Object.assign(taskMeasures, data);\n }\n },\n log(message, meta) {\n logBuffer.line(`[task ${taskIndex}] ${message}`, meta);\n },\n };\n\n let result: TaskResult | void = undefined;\n try {\n result = await task(ctx);\n record.data = mergeData({ ...taskMeasures, ...(result?.data ?? {}) }, phase);\n } catch (error) {\n record.status = 'error';\n if (error instanceof TaskError) {\n record.errorCode = error.code ?? error.name;\n record.data = mergeData({ ...taskMeasures, ...(error.data ?? {}) }, phase);\n if (error.steps?.length) frameworkSteps.push(...error.steps);\n } else {\n record.errorCode = getErrorCode(error);\n record.data = mergeData(\n { ...taskMeasures, errorMessage: error instanceof Error ? error.message : String(error) },\n phase,\n );\n }\n } finally {\n const endMs = Date.now();\n record.completedAt = new Date(endMs).toISOString();\n record.latencyMs =\n record.status === 'success' && result && typeof result.latencyMs === 'number'\n ? result.latencyMs\n : endMs - startedAtMs;\n const taskSteps = record.status === 'success' && result?.steps ? result.steps : [];\n const allSteps = [...frameworkSteps, ...taskSteps];\n // A task that declared no steps is recorded as a single implicit 'task'\n // step, matching the client worker's behavior.\n if (allSteps.length === 0) {\n allSteps.push({\n name: 'task',\n status: record.status === 'success' ? 'success' : 'error',\n startedAt: record.startedAt,\n completedAt: record.completedAt,\n latencyMs: record.latencyMs,\n errorCode: record.errorCode ?? null,\n data: Object.keys(taskMeasures).length > 0 ? { ...taskMeasures } : undefined,\n });\n }\n record.steps = allSteps;\n }\n\n return record;\n}\n","import type { JsonObject, TaskResultRecord } from '@benchsdk/client';\nimport type { BenchmarkRunOutcome } from './bench-config.js';\n\nexport type MetricValue = string | ((record: TaskResultRecord) => number | number[] | undefined);\n\nexport interface MetricScoring {\n name: string;\n value?: MetricValue;\n unit: string;\n ceiling: number;\n floor?: number;\n higherIsBetter?: boolean;\n weights: { median: number; p95: number; p99: number };\n trim?: number;\n}\n\nexport interface ScoringSpec {\n dimensions?: Record<string, unknown>;\n success?: (record: TaskResultRecord) => boolean;\n metrics: MetricScoring[];\n}\n\nexport interface BenchmarkScoreResult {\n provider: string;\n dimensions: JsonObject;\n metrics: { name: string; unit: string; median: number; p95: number; p99: number }[];\n scalars?: { name: string; value: number; unit: string }[];\n compositeScore: number;\n successRate: number;\n scoringVersion?: string;\n skipped: boolean;\n skipReason?: string;\n}\n\nexport type LowerIsBetter = (\n name: string,\n opts: {\n unit: string;\n ceiling: number;\n value?: MetricValue;\n weights: { median: number; p95: number; p99: number };\n trim?: number;\n },\n) => MetricScoring;\n\nexport type HigherIsBetter = (\n name: string,\n opts: {\n unit: string;\n floor?: number;\n ceiling: number;\n value?: MetricValue;\n weights: { median: number; p95: number; p99: number };\n trim?: number;\n },\n) => MetricScoring;\n\nfunction isFiniteNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v);\n}\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.max(0, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[Math.min(idx, sorted.length - 1)];\n}\n\nfunction computeStats(values: number[], trimPercent: number = 0.05): { median: number; p95: number; p99: number } {\n if (values.length === 0) return { median: 0, p95: 0, p99: 0 };\n\n const sorted = [...values].sort((a, b) => a - b);\n\n const trimCount = Math.floor(sorted.length * trimPercent);\n const trimmed = trimCount > 0 && sorted.length - 2 * trimCount > 0\n ? sorted.slice(trimCount, sorted.length - trimCount)\n : sorted;\n\n const mid = Math.floor(trimmed.length / 2);\n const median = trimmed.length % 2 === 0\n ? (trimmed[mid - 1] + trimmed[mid]) / 2\n : trimmed[mid];\n\n return { median, p95: percentile(trimmed, 95), p99: percentile(trimmed, 99) };\n}\n\nfunction toJsonObject(value: Record<string, unknown>): JsonObject {\n return JSON.parse(JSON.stringify(value ?? {})) as JsonObject;\n}\n\nfunction collectSamples(metric: MetricScoring, records: TaskResultRecord[]): number[] {\n const samples: number[] = [];\n for (const record of records) {\n const raw = typeof metric.value === 'function'\n ? metric.value(record)\n : record.data?.[metric.value ?? metric.name];\n\n if (Array.isArray(raw)) {\n for (const item of raw) {\n if (isFiniteNumber(item)) samples.push(item);\n }\n } else if (isFiniteNumber(raw)) {\n samples.push(raw);\n }\n }\n return samples;\n}\n\nfunction scoreStat(stat: number, metric: MetricScoring): number {\n if (metric.higherIsBetter) {\n const floor = metric.floor ?? 0;\n if (stat <= floor) return 0;\n if (stat >= metric.ceiling) return 100;\n return ((stat - floor) / (metric.ceiling - floor)) * 100;\n }\n return Math.max(0, 100 * (1 - stat / metric.ceiling));\n}\n\nexport const lowerIsBetter: LowerIsBetter = (name, opts) => ({\n name,\n ...opts,\n higherIsBetter: false,\n});\n\nexport const higherIsBetter: HigherIsBetter = (name, opts) => ({\n name,\n ...opts,\n higherIsBetter: true,\n});\n\nexport function score(outcome: BenchmarkRunOutcome, spec: ScoringSpec): BenchmarkScoreResult[] {\n const successFilter = spec.success ?? ((r: TaskResultRecord) => r.status === 'success');\n const dimensions = toJsonObject(spec.dimensions ?? {});\n const results: BenchmarkScoreResult[] = [];\n\n for (const { participant, records } of outcome.participants) {\n const passing = records.filter(successFilter);\n const successRate = records.length === 0 ? 0 : passing.length / records.length;\n const skipped = records.length === 0;\n\n let metricScoresSum = 0;\n const metrics: BenchmarkScoreResult['metrics'] = [];\n\n for (const metric of spec.metrics) {\n const samples = collectSamples(metric, passing);\n // A metric with no data points should not contribute to the composite\n // score; otherwise an empty lower-is-better metric would be scored as 100.\n if (samples.length === 0) {\n continue;\n }\n const { median, p95, p99 } = computeStats(samples, metric.trim ?? 0.05);\n const metricScore =\n metric.weights.median * scoreStat(median, metric) +\n metric.weights.p95 * scoreStat(p95, metric) +\n metric.weights.p99 * scoreStat(p99, metric);\n metricScoresSum += metricScore;\n\n metrics.push({ name: metric.name, unit: metric.unit, median, p95, p99 });\n }\n\n const compositeScore = successRate === 0 ? 0 : Math.round(metricScoresSum * successRate * 100) / 100;\n\n results.push({\n provider: participant,\n dimensions,\n metrics,\n compositeScore,\n successRate,\n skipped,\n });\n }\n\n return results;\n}\n","/**\n * Accumulates one text log per worker across a task's steps, uploaded once as a\n * `coordinator.log` artifact. Used by the runner's manual `round` mode, where\n * `client.runWorker` (which owns log upload in `participant` mode) is not in\n * play.\n */\nexport interface StepOutcome {\n stdout?: string;\n stderr?: string;\n error?: string;\n}\n\nexport class LogBuffer {\n private readonly lines: string[] = [];\n\n step(taskIndex: number, stepName: string, outcome: StepOutcome): void {\n const header = `[task ${taskIndex}] ${stepName}`;\n this.lines.push(`${new Date().toISOString()} ${header}`);\n if (outcome.stdout?.trim()) {\n this.lines.push(indent(outcome.stdout));\n }\n if (outcome.stderr?.trim()) {\n this.lines.push(indent(outcome.stderr, 'stderr: '));\n }\n if (outcome.error) {\n this.lines.push(indent(outcome.error, 'error: '));\n }\n }\n\n /** Appends a free-form narration line (backs the task context's `log`). */\n line(message: string, meta?: Record<string, unknown>): void {\n const suffix = meta && Object.keys(meta).length > 0 ? ` ${JSON.stringify(meta)}` : '';\n this.lines.push(`${new Date().toISOString()} ${message}${suffix}`);\n }\n\n isEmpty(): boolean {\n return this.lines.length === 0;\n }\n\n toText(): string {\n return this.lines.join('\\n') + '\\n';\n }\n}\n\nfunction indent(text: string, prefix = ''): string {\n return text\n .trimEnd()\n .split('\\n')\n .map((line) => ` ${prefix}${line}`)\n .join('\\n');\n}\n","/**\n * The author-facing entrypoint. `bench` is verbs-only — the benchmark and its\n * runs are implicit, never nouns you type:\n *\n * bench run <file.bench.ts> [--flags] execute a benchmark\n *\n * `run` imports a benchmark module, reads its `config` and `task` exports and\n * drives `runBenchmark`; CLI flags override the config's knobs and\n * `config.onComplete` (if any) fires once the run finishes. The benchmark is\n * declared in the file (`--shape` picks a named variant) and materialized on\n * run; a run is opened as a side effect, shared across sibling processes when\n * they pass the same `--run-key`. There are no imperative `create` commands.\n *\n * The executable wrapper lives in `bin.ts`; this module has no side effects so\n * it can be unit-tested by calling `runBenchmarkFile` directly.\n */\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { parseCliArgs, runBenchmark } from './runner.js';\nimport { NoAvailableParticipantsError } from './no-available-participants.js';\nimport type { BaseParticipant } from '@benchsdk/client';\nimport type { BenchmarkConfig, BenchmarkTask } from './bench-config.js';\n\nconst USAGE =\n 'Usage:\\n' +\n ' bench run <file.bench.ts> [--shape name] [--provider a,b] [--run-key key]\\n' +\n ' [--benchmark slug] [--name \"My benchmark\"]\\n' +\n ' [--iterations N] [--concurrency N] [--stagger-delay-ms N] [--group-by participant|round]\\n' +\n ' [--no-ingest | --dry-run]';\n\n/** A benchmark module is expected to export `config` and `task`. */\ninterface BenchmarkModule {\n config?: unknown;\n task?: unknown;\n default?: unknown;\n}\n\nfunction isBenchmarkConfig(value: unknown): value is BenchmarkConfig {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as { benchmarkSlug?: unknown; participants?: unknown };\n return typeof candidate.benchmarkSlug === 'string' && Array.isArray(candidate.participants);\n}\n\n/**\n * Dispatches one CLI invocation. Throws on bad usage / invalid exports and lets\n * `NoAvailableParticipantsError` propagate so the caller can map it to a clean\n * exit. Does not call `process.exit`.\n */\nexport async function runBenchmarkFile(argv: string[]): Promise<void> {\n const [command, ...rest] = argv;\n\n const [file, ...flags] = rest;\n if (command !== 'run' || !file || file.startsWith('-')) throw new Error(USAGE);\n\n const mod = (await import(pathToFileURL(resolve(process.cwd(), file)).href)) as BenchmarkModule;\n const config = mod.config;\n const task = mod.task ?? mod.default;\n\n if (!isBenchmarkConfig(config)) {\n throw new Error(`${file} must export a \\`config\\` created with defineBenchmarkConfig (with participants).`);\n }\n if (typeof task !== 'function') {\n throw new Error(`${file} must export a \\`task\\` created with defineTask.`);\n }\n\n await runBenchmark(config as BenchmarkConfig<BaseParticipant>, task as BenchmarkTask<BaseParticipant>, flags);\n}\n\n/** Executable entry: runs the file and maps outcomes to process exit codes. */\nexport async function run(argv: string[]): Promise<void> {\n try {\n await runBenchmarkFile(argv);\n // Provider SDKs can leave sockets/timers open; exit explicitly so a\n // finished run doesn't hang.\n process.exit(0);\n } catch (err) {\n if (err instanceof NoAvailableParticipantsError) {\n console.log(err.message);\n process.exit(0);\n }\n console.error('Benchmark failed:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["resolve","run","os","rampStartMs","ok","result"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/bench-config.ts","../src/no-available-participants.ts","../src/runner.ts","../src/scoring.ts","../src/log-buffer.ts","../src/cli.ts"],"sourcesContent":["export { defineBenchmarkConfig, defineTask, TaskError } from './bench-config.js';\ndeclare const __BENCH_VERSION__: string;\nexport const BENCHSDK_RUNNER_VERSION = __BENCH_VERSION__;\nexport type {\n BenchmarkConfig,\n BenchmarkTask,\n TaskContext,\n TaskResult,\n TaskStepOptions,\n Phase,\n GroupBy,\n ParticipantRecords,\n ResolvedRunConfig,\n BenchmarkRunOutcome,\n BenchmarkDisplayConfig,\n BenchmarkMetricDisplay,\n BenchmarkStepDisplay,\n BenchmarkOverviewDisplay,\n} from './bench-config.js';\nexport { NoAvailableParticipantsError } from './no-available-participants.js';\nexport { runBenchmark, parseCliArgs, mergeConfig } from './runner.js';\nexport type { CliArgs } from './runner.js';\nexport { run, runBenchmarkFile } from './cli.js';\nexport { score, lowerIsBetter, higherIsBetter, validateScoringSpec, ScoringSpecError, scoringConfigToSpec } from './scoring.js';\nexport type { ScoringSpec, MetricScoring, BenchmarkScoreResult, BenchmarkScoringConfig, BenchmarkScoringMetric, BenchmarkScoringSuccess, BenchmarkScoringWeights } from './scoring.js';\n","/**\n * A `*.bench.ts` file is the composition of a **config** and a **task**:\n *\n * export const config = defineBenchmarkConfig({ benchmarkSlug, participants, ... });\n * export const task = defineTask(async (ctx) => { await ctx.step('work', () => ...); });\n *\n * `defineBenchmarkConfig` holds the orchestration knobs (including the\n * participants and an optional `onComplete` hook); `defineTask` holds the\n * workload. The `bench run <file>` binary imports the module, reads those two\n * exports, and drives the run. There is no \"mode\": all orchestration shapes\n * emerge from the knobs.\n *\n * iterations total tasks to run (default 1)\n * concurrency max tasks in flight at once — 1 = sequential, N = burst (default 1)\n * staggerDelayMs delay each task's start by taskIndex * staggerDelayMs (default 0)\n *\n * Common shapes:\n * sequential { iterations: N, concurrency: 1 }\n * burst { iterations: N, concurrency: N }\n * staggered { iterations: N, concurrency: N, staggerDelayMs: 200 }\n *\n * A benchmark can name these variants up front via `shapes`, so one file backs\n * several platform benchmarks (`bench run <file> --shape burst`) without\n * restating each one's slug/name in scripts and CI.\n *\n * A task is comprised of steps, declared via `ctx.step` inside a task function\n * — it supports closures, conditionals and try/finally, so values (a created\n * sandbox, say) flow naturally between steps. A task that declares no steps is\n * recorded as a single implicit `task` step. Measurements reach the platform\n * via `ctx.measure(...)`; step return values are control flow and never\n * recorded.\n */\nimport type {\n BenchmarkLogOptions,\n DefineStepOptions,\n JsonObject,\n TaskResultRecord,\n TaskStepRecord,\n} from '@benchsdk/api';\nimport type { BaseParticipant } from '@benchsdk/worker';\nimport type { BenchmarkScoringConfig, HigherIsBetter, LowerIsBetter, ScoringSpec } from './scoring.js';\n\n/** How tasks are ordered across participants. */\nexport type GroupBy = 'participant' | 'round';\n\n/**\n * A named variant of a benchmark, selected with `--shape <name>`. A shape\n * carries only the parts that make it a distinct *benchmark* — its platform\n * identity plus any stable distinguishing knob (e.g. staggered's delay). The\n * scale knobs that vary per environment (`--iterations`, `--concurrency`) stay\n * on the invocation, so a shape never sets a value only to have the CLI\n * override it.\n */\nexport interface BenchmarkShape {\n /** Platform slug this shape reports under (e.g. 'sandbox-tti'). */\n slug: string;\n /** Display name shown on the platform; defaults to the slug. */\n name?: string;\n /** Default stagger delay (ms) for this shape; overridable with `--stagger-delay-ms`. */\n staggerDelayMs?: number;\n}\n\n/**\n * What a task returns: whatever it measured itself. This replaces the\n * assumption that the framework owns all timing. A plain data payload is\n * written explicitly as `{ data: {...} }`.\n */\nexport interface TaskResult {\n /** Free-form domain payload attached to the record (tokens, receipts, ...). */\n data?: JsonObject;\n /**\n * Pre-measured steps the task timed itself (e.g. socket phases).\n * Only honored in `groupBy: 'round'` runs, where the runner builds records\n * manually. In `groupBy: 'participant'` runs the platform worker\n * (`runWorker`) owns steps, so `steps` and `latencyMs` are ignored.\n */\n steps?: TaskStepRecord[];\n /** Task-owned overall latency; overrides framework wall-clock (round mode only). */\n latencyMs?: number;\n}\n\n/** Options for a single `ctx.step` invocation. */\nexport interface TaskStepOptions extends Omit<DefineStepOptions, 'concurrency' | 'stepConcurrency'> {\n /** Per-iteration timeout in milliseconds. If an invocation exceeds this, it is aborted and a `step_timeout` TaskError is thrown. */\n timeoutMs?: number;\n /** Number of times to invoke `fn` in parallel. Defaults to 1. When greater than 1, the step returns an array of results. */\n concurrency?: number;\n}\n\n/**\n * Throw this from a task to record a failure while preserving domain data and\n * any pre-measured steps (a plain thrown Error loses them).\n */\nexport class TaskError extends Error {\n readonly code?: string;\n readonly data?: JsonObject;\n readonly steps?: TaskStepRecord[];\n constructor(message: string, opts?: { code?: string; data?: JsonObject; steps?: TaskStepRecord[] }) {\n super(message);\n this.name = 'TaskError';\n this.code = opts?.code;\n this.data = opts?.data;\n this.steps = opts?.steps;\n }\n}\n\n/** Context handed to a benchmark `task` for a single iteration. */\nexport interface TaskContext<T extends BaseParticipant = BaseParticipant> {\n /** The participant this task is running for. */\n participant: T;\n /** Zero-based global task ordinal (matches the platform record's taskIndex). */\n taskIndex: number;\n /** Current phase name, when the benchmark declares `phases`. */\n phase?: string;\n /**\n * Runs `fn` as a named platform step. Mirrors `@benchsdk/worker`'s\n * `RunWorkerContext.step`; supports closures and try/finally. A `concurrency`\n * greater than 1 invokes `fn` that many times in parallel and returns an array.\n * `timeoutMs` aborts any invocation that exceeds it with a `step_timeout` TaskError.\n */\n step<R, C extends number = 1>(\n name: string,\n fn: () => Promise<R> | R,\n options?: TaskStepOptions & { concurrency?: C },\n ): Promise<C extends 1 ? R : R[]>;\n /**\n * Attaches a JSON measurement to the platform. Inside a `step` it lands on\n * that step's data; at task top-level it lands on the task record's data.\n */\n measure(data: JsonObject): void;\n /**\n * Appends a line to the worker log, uploaded as an artifact when the worker finishes.\n * `metaOrOptions` can be a metadata JSON object, or `{ level, meta }` to set a log level.\n */\n log(message: string, metaOrOptions?: JsonObject | BenchmarkLogOptions): void;\n}\n\nexport type BenchmarkTask<T extends BaseParticipant = BaseParticipant> = (\n ctx: TaskContext<T>,\n) => Promise<TaskResult | void> | TaskResult | void;\n\n/**\n * A named run segment with its own iteration count. Phases run in order; each\n * record is tagged with the phase name via `data.phase`, and `ctx.phase` lets\n * the task branch on identity instead of index arithmetic.\n */\nexport interface Phase {\n /** Phase name, tagged onto every record produced in this phase. */\n name: string;\n /** Iterations to run in this phase. */\n iterations: number;\n}\n\n/** One participant's collected task records from a run. */\nexport interface ParticipantRecords {\n participant: string;\n records: TaskResultRecord[];\n}\n\n/** The orchestration knobs a run actually used, after CLI overrides. */\nexport interface ResolvedRunConfig {\n iterations: number;\n /**\n * Iterations each phase runs, when the benchmark declares `phases` and\n * `--iterations` overrode their configured counts. A phase is one arm of a\n * comparison (a file size), so the flag scales every arm equally rather than\n * dividing a total between them.\n */\n phaseIterations?: number;\n concurrency: number;\n staggerDelayMs: number;\n groupBy: GroupBy;\n providers?: string[];\n}\n\n/** Display metadata for a single custom metric a benchmark reports via `ctx.measure`. */\nexport interface BenchmarkMetricDisplay {\n /** Stable metric key, matching the key in `ctx.measure` or `data`. */\n key: string;\n /** Human-readable label shown in the platform UI. */\n label: string;\n /** Optional unit shown after the value (e.g. `Mbps`, `/s`, `ms`). */\n unit?: string;\n /** Number of decimal places when formatting numeric values. Defaults to the display format. */\n decimals?: number;\n /** Whether higher or lower values rank better. */\n direction?: 'higher-better' | 'lower-better';\n /** Optional ordering hint for metric lists. */\n order?: number;\n}\n\n/** Display metadata for a single task lifecycle step. */\nexport interface BenchmarkStepDisplay {\n /** Stable step name, matching the string passed to `ctx.step`. */\n key: string;\n /** Human-readable label shown in the platform UI. */\n label: string;\n /** Optional ordering hint for step lists. */\n order?: number;\n}\n\n/** Display defaults for the benchmark overview page. */\nexport interface BenchmarkOverviewDisplay {\n /** Metric key to rank participants by by default (falls back to overall task latency). */\n defaultMetric?: string;\n /** Default overview layout. */\n defaultLayout?: 'ranking' | 'cards' | 'chart' | 'leaderboard';\n}\n\n/**\n * Optional platform display manifest. A `*.bench.ts` file owns not only how the\n * benchmark runs, but how it should be rendered, without a platform code change.\n */\nexport interface BenchmarkDisplayConfig {\n /** Metric catalog — labels, units, and ranking direction for `ctx.measure` keys. */\n metrics?: BenchmarkMetricDisplay[];\n /** Step catalog — human labels for lifecycle steps reported via `ctx.step`. */\n steps?: BenchmarkStepDisplay[];\n /** Overview defaults. */\n overview?: BenchmarkOverviewDisplay;\n}\n\n/**\n * Result of a benchmark run, passed to `config.onComplete`. Exposes the raw\n * per-participant records so completion hooks can write legacy local results.\n */\nexport interface BenchmarkRunOutcome {\n runId: string;\n /** Link to this run on the platform dashboard. */\n dashboardUrl: string;\n participants: ParticipantRecords[];\n config: ResolvedRunConfig;\n}\n\n/**\n * Orchestration config for a benchmark. Holds identity, the knobs, the\n * participants, and the optional completion hook — the workload lives in a\n * separate `defineTask`. `bench run <file>` reads the `config` and `task`\n * exports from the module and drives the run.\n */\nexport interface BenchmarkConfig<T extends BaseParticipant = BaseParticipant> {\n /**\n * Stable platform slug for this benchmark (e.g. 'sandbox-tti-local').\n * Selectable per run with `--shape` (or overridable with `--benchmark`), so\n * one entrypoint can report under several benchmarks.\n */\n benchmarkSlug: string;\n /** Human-readable name shown on the platform. Overridable with `--name`. */\n benchmarkName: string;\n /**\n * Named variants of this benchmark, selected with `--shape <name>`. Each\n * shape swaps in its own platform identity (and optional stable knob) while\n * reusing the same task and participants, so one bench file can back several\n * platform benchmarks without duplicating the slug/name triple across\n * package scripts and CI.\n */\n shapes?: Record<string, BenchmarkShape>;\n /**\n * Total tasks to run per participant. Default: 1. Mutually exclusive with\n * `phases` — when `phases` is set, total iterations = sum of phase iterations.\n */\n iterations?: number;\n /**\n * Named run segments (e.g. cold/warm). Runs in order; each record is tagged\n * with the phase name via `data.phase`. Mutually exclusive with `iterations`.\n */\n phases?: Phase[];\n /** Max tasks in flight at once. 1 = sequential, N = burst. Default: 1. */\n concurrency?: number;\n /** Delay each task's start by `taskIndex * staggerDelayMs`. Default: 0. */\n staggerDelayMs?: number;\n /**\n * Task ordering across participants. Default: 'participant' (run each\n * participant's tasks to completion, then the next). 'round' takes turns:\n * every participant runs its Nth task before anyone runs their (N+1)th, so\n * all participants' Nth tasks happen back-to-back under the same conditions.\n */\n groupBy?: GroupBy;\n /**\n * Default participant names to run when `--provider` is not passed. Omit to\n * run all env-available participants. `--provider` always overrides this.\n */\n defaultProviders?: string[];\n /** The participants this benchmark can run against. `--provider` selects a subset by name. */\n participants: T[];\n /**\n * Static run-level dimensions copied into the submitted summary (e.g.\n * `{ file_size: '10MB' }`). Useful for distinguishing runs of the same\n * benchmark that differ by an external parameter.\n */\n dimensions?: Record<string, unknown>;\n /**\n * Run-level scoring hook, called once with `lowerIsBetter` and `higherIsBetter`\n * primitives after the outcome is assembled but before `onComplete`. Use it to\n * define how the run should be scored and reported to the platform.\n */\n onScore?: (lowerIsBetter: LowerIsBetter, higherIsBetter: HigherIsBetter) => ScoringSpec | Promise<ScoringSpec>;\n /**\n * Run-level completion hook, called once with the full outcome after every\n * participant finishes. Use it for aggregate output (legacy JSON/SVG\n * writers). This is the run-level counterpart to per-step `ctx.measure`.\n */\n onComplete?: (outcome: BenchmarkRunOutcome) => void | Promise<void>;\n /**\n * Serializable scoring spec uploaded to the platform. When provided without\n * `onScore`, the runner computes the run summary from this spec automatically.\n * The platform can recompute `compositeScore` from the same spec at read time.\n */\n scoring?: BenchmarkScoringConfig;\n /**\n * Custom CLI flags this benchmark reads from `process.argv` (e.g. `--file-size`).\n * Declaring them lets the runner distinguish intentional pass-through flags\n * from typos and report unknown flags accurately.\n */\n customCliFlags?: readonly string[];\n /**\n * Optional display manifest. Lets the bench author configure metric labels,\n * step labels, and overview defaults without editing the platform.\n */\n display?: BenchmarkDisplayConfig;\n}\n\nfunction assertNonEmptyString(value: unknown, field: string): string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new Error(`${field} must be a non-empty string`);\n }\n return value;\n}\n\nfunction assertOnlyAllowedKeys(value: Record<string, unknown>, allowed: readonly string[], field: string): void {\n for (const key of Object.keys(value)) {\n if (!allowed.includes(key)) {\n throw new Error(`${field} contains unexpected key: '${key}'`);\n }\n }\n}\n\nfunction assertPositiveInt(value: number | undefined, field: string): void {\n if (value === undefined) return;\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`${field} must be an integer >= 1 (got ${value})`);\n }\n}\n\nfunction assertFiniteNumber(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new Error(`${field} must be a finite number (got ${value})`);\n }\n return value;\n}\n\nfunction validateBenchmarkScoringConfig(scoring: BenchmarkScoringConfig, display?: BenchmarkDisplayConfig): void {\n if (!Array.isArray(scoring.metrics) || scoring.metrics.length === 0) {\n throw new Error('scoring.metrics must be a non-empty array');\n }\n if (scoring.success !== undefined) {\n const requireData = scoring.success.requireData;\n if (requireData === null || typeof requireData !== 'object' || Array.isArray(requireData)) {\n throw new Error('scoring.success.requireData must be a plain object');\n }\n if (Object.keys(requireData).length === 0) {\n throw new Error('scoring.success.requireData must declare at least one data field');\n }\n for (const [key, value] of Object.entries(requireData)) {\n const type = typeof value;\n if (type !== 'string' && type !== 'number' && type !== 'boolean') {\n throw new Error(\n `scoring.success.requireData.${key} must be a string, number, or boolean (got ${type})`,\n );\n }\n }\n }\n const seen = new Set<string>();\n let totalWeight = 0;\n for (let i = 0; i < scoring.metrics.length; i++) {\n const metric = scoring.metrics[i];\n if (metric === null || typeof metric !== 'object' || Array.isArray(metric)) {\n throw new Error(`scoring.metrics[${i}] must be an object`);\n }\n const key = metric.key;\n if (typeof key !== 'string' || key.trim() === '') {\n throw new Error(`scoring.metrics[${i}].key must be a non-empty string`);\n }\n if (seen.has(key)) {\n throw new Error(`duplicate scoring metric key: ${key}`);\n }\n seen.add(key);\n // Unit is optional; when display.metrics is also declared it is the\n // canonical source and the scoring metric's unit must not contradict it.\n const displayMetrics = Array.isArray(display?.metrics) ? display!.metrics : undefined;\n const displayMetric = displayMetrics?.find((m) => m?.key === key);\n if (metric.unit !== undefined) {\n if (typeof metric.unit !== 'string') {\n throw new Error(`scoring.metrics[${i}].unit must be a string`);\n }\n if (displayMetric?.unit !== undefined && metric.unit !== displayMetric.unit) {\n throw new Error(\n `scoring.metrics[${i}].unit '${metric.unit}' conflicts with display.metrics[${i}].unit '${displayMetric.unit}' for key '${key}'`,\n );\n }\n }\n assertFiniteNumber(metric.ceiling, `scoring.metrics[${i}].ceiling`);\n if (metric.floor !== undefined) {\n assertFiniteNumber(metric.floor, `scoring.metrics[${i}].floor`);\n }\n if (metric.weights === null || typeof metric.weights !== 'object' || Array.isArray(metric.weights)) {\n throw new Error(`scoring.metrics[${i}].weights must be an object`);\n }\n const median = assertFiniteNumber(metric.weights.median, `scoring.metrics[${i}].weights.median`);\n const p95 = assertFiniteNumber(metric.weights.p95, `scoring.metrics[${i}].weights.p95`);\n const p99 = assertFiniteNumber(metric.weights.p99, `scoring.metrics[${i}].weights.p99`);\n if (median < 0 || p95 < 0 || p99 < 0) {\n throw new Error(`scoring.metrics[${i}].weights must be non-negative`);\n }\n totalWeight += median + p95 + p99;\n if (metric.trim !== undefined) {\n assertFiniteNumber(metric.trim, `scoring.metrics[${i}].trim`);\n }\n }\n if (Math.abs(totalWeight - 1) > 0.01) {\n throw new Error(`scoring metric weights must sum to 1.0 (got ${totalWeight.toFixed(3)})`);\n }\n}\n\n/** Validates `config` at file-evaluation time so mistakes surface immediately. */\nexport function defineBenchmarkConfig<T extends BaseParticipant = BaseParticipant>(\n config: BenchmarkConfig<T>,\n): BenchmarkConfig<T> {\n if (!config.benchmarkSlug || typeof config.benchmarkSlug !== 'string') {\n throw new Error('benchmarkSlug is required');\n }\n if (!config.benchmarkName || typeof config.benchmarkName !== 'string') {\n throw new Error('benchmarkName is required');\n }\n if (config.phases !== undefined) {\n if (config.iterations !== undefined) {\n throw new Error('phases and iterations are mutually exclusive');\n }\n if (!Array.isArray(config.phases) || config.phases.length === 0) {\n throw new Error('phases must be a non-empty array');\n }\n const seen = new Set<string>();\n for (const phase of config.phases) {\n if (!phase.name || typeof phase.name !== 'string') {\n throw new Error('each phase requires a non-empty name');\n }\n if (seen.has(phase.name)) {\n throw new Error(`duplicate phase name: ${phase.name}`);\n }\n seen.add(phase.name);\n assertPositiveInt(phase.iterations, `phase '${phase.name}' iterations`);\n }\n }\n assertPositiveInt(config.iterations, 'iterations');\n assertPositiveInt(config.concurrency, 'concurrency');\n if (config.staggerDelayMs !== undefined && (!Number.isFinite(config.staggerDelayMs) || config.staggerDelayMs < 0)) {\n throw new Error(`staggerDelayMs must be a number >= 0 (got ${config.staggerDelayMs})`);\n }\n if (config.groupBy !== undefined && config.groupBy !== 'participant' && config.groupBy !== 'round') {\n throw new Error(`groupBy must be 'participant' or 'round' (got ${config.groupBy})`);\n }\n if (config.shapes !== undefined) {\n for (const [shapeName, shape] of Object.entries(config.shapes)) {\n if (!shape.slug || !/^[a-z0-9][a-z0-9-]*$/.test(shape.slug)) {\n throw new Error(`shape '${shapeName}' needs a lowercase slug (got ${JSON.stringify(shape.slug)})`);\n }\n if (shape.name !== undefined && (typeof shape.name !== 'string' || shape.name.trim() === '')) {\n throw new Error(`shape '${shapeName}' name must be a non-empty string`);\n }\n if (shape.staggerDelayMs !== undefined && (!Number.isFinite(shape.staggerDelayMs) || shape.staggerDelayMs < 0)) {\n throw new Error(`shape '${shapeName}' staggerDelayMs must be a number >= 0 (got ${shape.staggerDelayMs})`);\n }\n }\n }\n if (config.dimensions !== undefined) {\n if (config.dimensions === null || typeof config.dimensions !== 'object' || Array.isArray(config.dimensions)) {\n throw new Error('dimensions must be a plain object');\n }\n }\n if (config.scoring !== undefined) {\n validateBenchmarkScoringConfig(config.scoring, config.display);\n }\n if (config.customCliFlags !== undefined) {\n if (!Array.isArray(config.customCliFlags) || !config.customCliFlags.every((f) => typeof f === 'string' && f.startsWith('--'))) {\n throw new Error('customCliFlags must be an array of strings starting with \"--\"');\n }\n }\n if (config.display !== undefined) {\n if (typeof config.display !== 'object' || config.display === null || Array.isArray(config.display)) {\n throw new Error('display must be an object');\n }\n assertOnlyAllowedKeys(config.display as unknown as Record<string, unknown>, ['metrics', 'steps', 'overview'], 'display');\n const displayMetricKeys = new Set<string>();\n if (config.display.metrics !== undefined) {\n if (!Array.isArray(config.display.metrics)) {\n throw new Error('display.metrics must be an array');\n }\n for (let i = 0; i < config.display.metrics.length; i++) {\n const metric = config.display.metrics[i];\n if (metric === null || typeof metric !== 'object' || Array.isArray(metric)) {\n throw new Error(`display.metrics[${i}] must be an object`);\n }\n assertOnlyAllowedKeys(metric as unknown as Record<string, unknown>, ['key', 'label', 'unit', 'direction', 'decimals', 'order'], `display.metrics[${i}]`);\n const key = assertNonEmptyString(metric.key, `display.metrics[${i}].key`);\n if (displayMetricKeys.has(key)) {\n throw new Error(`duplicate display metric key: ${key}`);\n }\n displayMetricKeys.add(key);\n assertNonEmptyString(metric.label, `display.metrics[${i}].label`);\n if (metric.unit !== undefined && typeof metric.unit !== 'string') {\n throw new Error(`display.metrics[${i}].unit must be a string`);\n }\n if (metric.direction !== undefined && metric.direction !== 'higher-better' && metric.direction !== 'lower-better') {\n throw new Error(`display.metrics[${i}].direction must be 'higher-better' or 'lower-better'`);\n }\n if (metric.decimals !== undefined && (!Number.isInteger(metric.decimals) || metric.decimals < 0)) {\n throw new Error(`display.metrics[${i}].decimals must be a non-negative integer`);\n }\n if (metric.order !== undefined && (!Number.isInteger(metric.order) || metric.order < 0)) {\n throw new Error(`display.metrics[${i}].order must be a non-negative integer`);\n }\n }\n }\n if (config.display.steps !== undefined) {\n if (!Array.isArray(config.display.steps)) {\n throw new Error('display.steps must be an array');\n }\n const seenStepKeys = new Set<string>();\n for (let i = 0; i < config.display.steps.length; i++) {\n const step = config.display.steps[i];\n if (step === null || typeof step !== 'object' || Array.isArray(step)) {\n throw new Error(`display.steps[${i}] must be an object`);\n }\n assertOnlyAllowedKeys(step as unknown as Record<string, unknown>, ['key', 'label', 'order'], `display.steps[${i}]`);\n const key = assertNonEmptyString(step.key, `display.steps[${i}].key`);\n if (seenStepKeys.has(key)) {\n throw new Error(`duplicate display step key: ${key}`);\n }\n seenStepKeys.add(key);\n assertNonEmptyString(step.label, `display.steps[${i}].label`);\n if (step.order !== undefined && (!Number.isInteger(step.order) || step.order < 0)) {\n throw new Error(`display.steps[${i}].order must be a non-negative integer`);\n }\n }\n }\n if (config.display.overview !== undefined) {\n if (typeof config.display.overview !== 'object' || config.display.overview === null || Array.isArray(config.display.overview)) {\n throw new Error('display.overview must be an object');\n }\n assertOnlyAllowedKeys(config.display.overview as unknown as Record<string, unknown>, ['defaultMetric', 'defaultLayout'], 'display.overview');\n const { defaultMetric, defaultLayout } = config.display.overview;\n if (defaultMetric !== undefined) {\n const metric = assertNonEmptyString(defaultMetric, 'display.overview.defaultMetric');\n // The default metric can reference any declared custom metric, or the\n // platform-level composite score / overall task latency sentinels.\n const validDefaultMetrics = new Set(displayMetricKeys);\n validDefaultMetrics.add('compositeScore');\n validDefaultMetrics.add('task');\n if (config.display.metrics !== undefined && !validDefaultMetrics.has(metric)) {\n throw new Error(`display.overview.defaultMetric '${metric}' is not declared in display.metrics and is not a known default (compositeScore, task)`);\n }\n }\n if (defaultLayout !== undefined && !['ranking', 'cards', 'chart', 'leaderboard'].includes(defaultLayout)) {\n throw new Error(\"display.overview.defaultLayout must be 'ranking', 'cards', 'chart', or 'leaderboard'\");\n }\n }\n }\n if (config.display?.overview?.defaultMetric === 'compositeScore' && config.scoring === undefined && config.onScore === undefined) {\n throw new Error(\"display.overview.defaultMetric cannot be 'compositeScore' without config.scoring or config.onScore\");\n }\n return config;\n}\n\n/**\n * Declares the workload for a benchmark: a function invoked once per iteration.\n * Steps are named via `ctx.step`, which supports closures and try/finally so\n * values flow naturally between steps.\n *\n * export const task = defineTask(async (ctx) => {\n * const sandbox = await ctx.step('create', () => provider.create());\n * try { await ctx.step('exec', () => sandbox.run('node -v')); }\n * finally { await ctx.step('destroy', () => sandbox.destroy()); }\n * });\n */\nexport function defineTask<T extends BaseParticipant = BaseParticipant>(\n task: BenchmarkTask<T>,\n): BenchmarkTask<T> {\n if (typeof task !== 'function') {\n throw new Error('defineTask requires a task function.');\n }\n return task;\n}\n","/**\n * Thrown when every selected participant was env-gated out, i.e. none of their\n * `requiredEnvVars` are set. This is a \"nothing to do\" outcome rather than a\n * failure — a benchmark job for a provider whose credentials aren't provisioned\n * should skip, not go red — so callers are expected to exit 0 on it.\n */\nexport class NoAvailableParticipantsError extends Error {\n readonly skipped: { name: string; missing: string[] }[];\n\n constructor(skipped: { name: string; missing: string[] }[]) {\n super(\n `No participants have their required env vars set — nothing to run${\n skipped.length > 0 ? ` (skipped: ${skipped.map((s) => s.name).join(', ')})` : ''\n }.`,\n );\n this.name = 'NoAvailableParticipantsError';\n this.skipped = skipped;\n }\n}\n","/**\n * CLI runner for `defineBenchmark` configs. Owns all platform orchestration\n * (upsert benchmark, create run, plan + drive workers per participant) so a\n * `*.bench.ts` file only has to declare its config and task. The orchestration\n * knobs (iterations / concurrency / staggerDelayMs / groupBy) can be overridden\n * per-invocation via CLI flags.\n *\n * Two execution orderings, chosen by `groupBy`:\n * 'participant' (default) — each participant's tasks run to completion via\n * `runWorker(client, ...)` (with its pooled concurrency + heartbeat reporting)\n * before the next participant starts.\n * 'round' — participants take turns: every participant runs its Nth task\n * before anyone starts their (N+1)th, so all Nth tasks happen back-to-back\n * under the same conditions. Driven manually via one `BenchmarkReporter`\n * per participant.\n */\nimport { execSync } from 'node:child_process';\nimport os from 'node:os';\nimport { createBenchmarkClient } from '@benchsdk/api';\nimport { resolveAuth } from '@benchsdk/cli';\nimport {\n BenchmarkReporter,\n createSystemMetricsCollector,\n filterParticipantsByEnv,\n runWorker,\n selectParticipants,\n} from '@benchsdk/worker';\nimport type { BenchmarkSystemMetricsCollector, BenchmarkSystemMetricsSample } from '@benchsdk/worker';\nimport { NoAvailableParticipantsError } from './no-available-participants.js';\nimport { higherIsBetter, lowerIsBetter, score, ScoringSpecError, scoringConfigToSpec } from './scoring.js';\nimport type {\n BenchmarkClient,\n BenchmarkLogOptions,\n BenchmarkStepOutcome,\n DefineStepOptions,\n JsonObject,\n RunWorkerContext,\n TaskResultRecord,\n TaskStepRecord,\n} from '@benchsdk/api';\nimport type { BaseParticipant } from '@benchsdk/worker';\nimport { TaskError } from './bench-config.js';\nimport type {\n BenchmarkConfig,\n BenchmarkRunOutcome,\n BenchmarkShape,\n BenchmarkTask,\n GroupBy,\n ParticipantRecords,\n ResolvedRunConfig,\n TaskContext,\n TaskResult,\n TaskStepOptions,\n} from './bench-config.js';\nimport { LogBuffer } from './log-buffer.js';\n\nexport interface CliArgs {\n /** Which platform benchmark to report as (`--benchmark`, aka the benchmark slug). */\n benchmark?: string;\n name?: string;\n /** Named variant from the bench file's `shapes` (`--shape`), swapping in its identity. */\n shape?: string;\n /**\n * Idempotency key (`--run-key`): sibling processes passing the same key share\n * one run (get-or-created), instead of each opening its own.\n */\n runKey?: string;\n iterations?: number;\n concurrency?: number;\n staggerDelayMs?: number;\n groupBy?: GroupBy;\n /** Participant names from `--provider a,b` (repeatable). */\n providers?: string[];\n /** When true, run locally and do not ingest/report to the platform. */\n noIngest?: boolean;\n}\n\nfunction isEnvNoIngest(): boolean {\n const v = process.env.BENCHSDK_NO_INGEST;\n return v === '1' || v?.toLowerCase() === 'true';\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Runs an array of async functions with a bounded concurrency limit.\n * Results are returned in the same order as the input array.\n */\nfunction runWithConcurrency<T>(fns: Array<() => Promise<T>>, limit: number): Promise<T[]> {\n if (limit >= fns.length || fns.length === 0) {\n return Promise.all(fns.map((fn) => fn()));\n }\n\n const results = new Array<T>(fns.length);\n let running = 0;\n let completed = 0;\n let nextIndex = 0;\n\n return new Promise((resolve, reject) => {\n const runNext = () => {\n if (completed === fns.length) {\n resolve(results);\n return;\n }\n while (running < limit && nextIndex < fns.length) {\n const index = nextIndex++;\n running++;\n fns[index]().then(\n (value) => {\n results[index] = value;\n running--;\n completed++;\n runNext();\n },\n (error) => reject(error),\n );\n }\n };\n runNext();\n });\n}\n\nfunction getErrorCode(error: unknown): string {\n if (error instanceof Error && 'code' in error && typeof (error as { code: unknown }).code === 'string' && (error as { code: string }).code) {\n return (error as { code: string }).code;\n }\n if (error instanceof Error && error.name) return error.name;\n return 'ERROR';\n}\n\nfunction isTaskError(error: unknown): error is TaskError {\n return error instanceof Error && (error instanceof TaskError || error.name === 'TaskError');\n}\n\nconst STEP_OUTCOME_KEYS = new Set(['stdout', 'stderr', 'error', 'exitCode', 'code', 'signal', 'pid']);\n\nfunction isStepOutcome(value: unknown): value is BenchmarkStepOutcome {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const o = value as Record<string, unknown>;\n const keys = Object.keys(o);\n if (keys.length === 0) return false;\n if (!keys.every((k) => STEP_OUTCOME_KEYS.has(k))) return false;\n return typeof o.stdout === 'string' || typeof o.stderr === 'string' || typeof o.error === 'string';\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number, name: string): Promise<T> {\n return new Promise((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new TaskError(`Step \"${name}\" timed out after ${ms}ms`, { code: 'step_timeout' })),\n ms,\n );\n promise.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error) => {\n clearTimeout(timer);\n reject(error);\n },\n );\n });\n}\n\nasync function runStepInvocations<R>(\n name: string,\n fn: () => Promise<R> | R,\n options: TaskStepOptions | undefined,\n): Promise<R | R[]> {\n const requestedConcurrency = options?.concurrency;\n if (requestedConcurrency !== undefined && (!Number.isInteger(requestedConcurrency) || requestedConcurrency < 1)) {\n throw new Error(`step \"${name}\" concurrency must be an integer >= 1 (got ${requestedConcurrency})`);\n }\n const timeoutMs = options?.timeoutMs;\n if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0)) {\n throw new Error(`step \"${name}\" timeoutMs must be a number >= 0 (got ${timeoutMs})`);\n }\n\n const count = requestedConcurrency ?? 1;\n const invocations = Array.from({ length: count }, () => {\n const promise = Promise.resolve().then(() => fn());\n if (timeoutMs === undefined) return promise;\n return withTimeout(promise, timeoutMs, name);\n });\n\n if (count === 1) {\n return invocations[0];\n }\n\n const outcomes = await Promise.allSettled(invocations);\n const results: R[] = [];\n let firstError: unknown;\n for (const outcome of outcomes) {\n if (outcome.status === 'fulfilled') {\n results.push(outcome.value);\n } else if (firstError === undefined) {\n firstError = outcome.reason;\n }\n }\n if (firstError !== undefined) throw firstError;\n return results;\n}\n\nasync function runStepWithClient<R, C extends number = 1>(\n clientStep: RunWorkerContext['step'],\n name: string,\n fn: () => Promise<R> | R,\n options?: TaskStepOptions & { concurrency?: C },\n): Promise<C extends 1 ? R : R[]> {\n const { concurrency: runnerConcurrency, timeoutMs, ...clientOptions } = options ?? {};\n const clientStepOptions: DefineStepOptions = {\n ...clientOptions,\n timeoutMs,\n stepConcurrency: runnerConcurrency,\n };\n const result = await clientStep(name, () => runStepInvocations(name, fn, options), clientStepOptions);\n return result as C extends 1 ? R : R[];\n}\n\n/**\n * Parses the orchestration flags this runner understands, rejecting unknown\n * flags. Supports both `--flag value` and `--flag=value`; `--provider` accepts\n * a comma-separated list and may be repeated.\n *\n * `allowedCustomFlags` lists pass-through flags the benchmark file reads from\n * `process.argv` itself; the runner validates and skips them without choking on\n * their values.\n */\nexport function parseCliArgs(argv: string[], allowedCustomFlags?: readonly string[]): CliArgs {\n const args: CliArgs = {};\n const unknown: string[] = [];\n const allowed = new Set(allowedCustomFlags ?? []);\n\n const readValue = (raw: string, i: number): { value: string; nextIndex: number } => {\n const eq = raw.indexOf('=');\n if (eq !== -1) return { value: raw.slice(eq + 1), nextIndex: i };\n return { value: argv[i + 1] ?? '', nextIndex: i + 1 };\n };\n\n const intFlag = (raw: string, flag: string): number => {\n if (raw.trim() === '') throw new Error(`${flag} expects a value`);\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 1) throw new Error(`${flag} expects an integer >= 1 (got \"${raw}\")`);\n return n;\n };\n\n const nonNegFlag = (raw: string, flag: string): number => {\n if (raw.trim() === '') throw new Error(`${flag} expects a value`);\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 0) throw new Error(`${flag} expects a number >= 0 (got \"${raw}\")`);\n return n;\n };\n\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n const name = arg.includes('=') ? arg.slice(0, arg.indexOf('=')) : arg;\n switch (name) {\n // `--slug` is the pre-`--benchmark` spelling, kept working for existing scripts.\n case '--slug':\n case '--benchmark': {\n const { value, nextIndex } = readValue(arg, i);\n if (!/^[a-z0-9][a-z0-9-]*$/.test(value)) {\n throw new Error(`${name} expects a lowercase benchmark slug (got \"${value}\")`);\n }\n args.benchmark = value;\n i = nextIndex;\n break;\n }\n case '--name': {\n const { value, nextIndex } = readValue(arg, i);\n if (value.trim() === '') throw new Error('--name expects a value');\n args.name = value;\n i = nextIndex;\n break;\n }\n case '--shape': {\n const { value, nextIndex } = readValue(arg, i);\n if (value.trim() === '') throw new Error('--shape expects a value');\n args.shape = value;\n i = nextIndex;\n break;\n }\n case '--run-key': {\n const { value, nextIndex } = readValue(arg, i);\n if (value.trim() === '') throw new Error('--run-key expects a value');\n args.runKey = value;\n i = nextIndex;\n break;\n }\n case '--iterations': {\n const { value, nextIndex } = readValue(arg, i);\n args.iterations = intFlag(value, '--iterations');\n i = nextIndex;\n break;\n }\n case '--concurrency': {\n const { value, nextIndex } = readValue(arg, i);\n args.concurrency = intFlag(value, '--concurrency');\n i = nextIndex;\n break;\n }\n case '--stagger-delay-ms': {\n const { value, nextIndex } = readValue(arg, i);\n args.staggerDelayMs = nonNegFlag(value, '--stagger-delay-ms');\n i = nextIndex;\n break;\n }\n case '--group-by': {\n const { value, nextIndex } = readValue(arg, i);\n if (value !== 'participant' && value !== 'round') {\n throw new Error(`--group-by expects 'participant' or 'round' (got \"${value}\")`);\n }\n args.groupBy = value;\n i = nextIndex;\n break;\n }\n case '--provider': {\n const { value, nextIndex } = readValue(arg, i);\n const names = value.split(',').map((s) => s.trim()).filter(Boolean);\n args.providers = [...(args.providers ?? []), ...names];\n i = nextIndex;\n break;\n }\n case '--no-ingest':\n case '--dry-run':\n args.noIngest = true;\n break;\n default: {\n if (allowed.has(name)) {\n // Skip the flag's value (if supplied as a separate token) so the\n // benchmark file can read it from process.argv itself.\n if (!arg.includes('=')) {\n const next = argv[i + 1];\n if (next && !next.startsWith('-')) {\n i++;\n }\n }\n } else {\n unknown.push(name);\n // Unknown flags that take a value shouldn't report the value as a\n // separate unknown flag.\n if (!arg.includes('=')) {\n const next = argv[i + 1];\n if (next && !next.startsWith('-')) {\n i++;\n }\n }\n }\n break;\n }\n }\n }\n\n if (unknown.length > 0) {\n throw new Error(`Unknown flag(s): ${unknown.join(', ')}`);\n }\n\n if (!args.noIngest && isEnvNoIngest()) {\n args.noIngest = true;\n }\n return args;\n}\n\n/** Merges CLI overrides over config defaults, filling in knob fallbacks. */\nexport function mergeConfig<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n args: CliArgs,\n): ResolvedRunConfig {\n // `--iterations` applies per phase: phases are the arms of one comparison, so\n // scaling them equally keeps the arms comparable, where splitting a total\n // between them would shrink each arm as arms are added. A benchmark that\n // sizes its arms differently (cold probes more than warm) meant that\n // difference, so its counts win over the flag.\n const phases = config.phases;\n const unevenPhases = phases !== undefined && phases.some((p) => p.iterations !== phases[0].iterations);\n if (unevenPhases && args.iterations !== undefined) {\n console.warn('--iterations is ignored because this benchmark sizes its phases individually.');\n }\n const phaseIterations = phases !== undefined && !unevenPhases ? args.iterations : undefined;\n const phaseTotal =\n phases !== undefined\n ? (phaseIterations !== undefined\n ? phaseIterations * phases.length\n : phases.reduce((sum, p) => sum + p.iterations, 0))\n : undefined;\n const resolved: ResolvedRunConfig = {\n iterations: phaseTotal ?? args.iterations ?? config.iterations ?? 1,\n phaseIterations,\n concurrency: args.concurrency ?? config.concurrency ?? 1,\n staggerDelayMs: args.staggerDelayMs ?? config.staggerDelayMs ?? 0,\n groupBy: args.groupBy ?? config.groupBy ?? 'participant',\n providers: args.providers ?? config.defaultProviders,\n };\n if (!Number.isInteger(resolved.iterations) || resolved.iterations < 1) {\n throw new Error(`iterations must be an integer >= 1 (got ${resolved.iterations})`);\n }\n if (!Number.isInteger(resolved.concurrency) || resolved.concurrency < 1) {\n throw new Error(`concurrency must be an integer >= 1 (got ${resolved.concurrency})`);\n }\n return resolved;\n}\n\n/** One scheduled task slot: which task to run and (optionally) under which phase. */\ninterface Slot<T extends BaseParticipant = BaseParticipant> {\n phase?: string;\n task: BenchmarkTask<T>;\n}\n\n/**\n * Flattens a config into an ordered list of task slots. With `phases`, each\n * phase contributes its own iterations' worth of slots tagged with its name\n * (framework owns the phase boundary — no index arithmetic in the task).\n * Without phases, the task is repeated `iterations` times.\n */\nfunction buildSchedule<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n resolved: ResolvedRunConfig,\n task: BenchmarkTask<T>,\n): Slot<T>[] {\n if (config.phases?.length) {\n return config.phases.flatMap((phase) =>\n Array.from({ length: resolved.phaseIterations ?? phase.iterations }, () => ({\n phase: phase.name,\n task,\n })),\n );\n }\n return Array.from({ length: resolved.iterations }, () => ({ phase: undefined, task }));\n}\n\ntype OnResult = (record: TaskResultRecord, meta: { iterations: number; participant: string }) => void;\n\nfunction defaultOnResult(record: TaskResultRecord, meta: { iterations: number; participant: string }): void {\n const n = record.taskIndex + 1;\n if (record.status === 'success') {\n const data = record.data && Object.keys(record.data).length > 0 ? ` ${JSON.stringify(record.data)}` : '';\n console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: success${data}`);\n } else {\n console.log(` [${meta.participant}] Task ${n}/${meta.iterations}: FAILED — ${record.errorCode ?? 'unknown error'}`);\n }\n}\n\n/**\n * Resolves `--shape <name>` against the config's declared `shapes`. Throws with\n * the known names if the shape is unknown, so a typo fails loudly instead of\n * silently running the base benchmark.\n */\nfunction resolveShape<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n shapeName: string | undefined,\n): BenchmarkShape | undefined {\n if (!shapeName) return undefined;\n const shape = config.shapes?.[shapeName];\n if (!shape) {\n const known = Object.keys(config.shapes ?? {});\n throw new Error(\n known.length > 0\n ? `Unknown --shape \"${shapeName}\". Known shapes: ${known.join(', ')}.`\n : `Unknown --shape \"${shapeName}\": this benchmark declares no shapes.`,\n );\n }\n return shape;\n}\n\n/**\n * Swaps a shape's identity (and its stable knob) into the config. Only the\n * parts that make it a distinct benchmark move here; scale knobs stay on the\n * CLI, so `mergeConfig` still lets `--concurrency`/`--iterations` win.\n */\nfunction applyShape<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n shape: BenchmarkShape | undefined,\n): BenchmarkConfig<T> {\n if (!shape) return config;\n return {\n ...config,\n benchmarkSlug: shape.slug,\n benchmarkName: shape.name ?? shape.slug,\n ...(shape.staggerDelayMs !== undefined ? { staggerDelayMs: shape.staggerDelayMs } : {}),\n };\n}\n\n/** Applies the `--benchmark`/`--name` overrides, so one entrypoint can report under several benchmarks. */\nfunction applyIdentityOverrides<T extends BaseParticipant>(\n fileConfig: BenchmarkConfig<T>,\n args: CliArgs,\n): BenchmarkConfig<T> {\n return {\n ...fileConfig,\n ...(args.benchmark ? { benchmarkSlug: args.benchmark } : {}),\n ...(args.name ? { benchmarkName: args.name } : {}),\n };\n}\n\nfunction dashboardUrlFor(baseUrl: string, organizationSlug: string, benchmarkSlug: string, runId: string): string {\n return `${baseUrl.replace(/\\/api\\/v1\\/?$/, '')}/${organizationSlug}/benchmarks/${benchmarkSlug}/runs/${runId}`;\n}\n\n/** The participants a run covers: `--provider` selection, minus any whose env vars are unset. */\nfunction resolveParticipants<T extends BaseParticipant>(config: BenchmarkConfig<T>, resolved: ResolvedRunConfig): T[] {\n const { available, skipped } = filterParticipantsByEnv(selectParticipants(config.participants, resolved.providers));\n for (const s of skipped) {\n console.log(`Skipping ${s.name}: missing ${s.missing.join(', ')}`);\n }\n if (available.length === 0) throw new NoAvailableParticipantsError(skipped);\n return available;\n}\n\n/** Builds a JSON-serializable snapshot of the resolved run execution config. */\nfunction runConfigToJson<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n resolved: ResolvedRunConfig,\n participants: string[],\n): JsonObject {\n const phases = config.phases?.map((phase) => ({\n name: phase.name,\n iterations: resolved.phaseIterations ?? phase.iterations,\n }));\n const runConfig = {\n benchmarkSlug: config.benchmarkSlug,\n benchmarkName: config.benchmarkName,\n ...(resolved.phaseIterations !== undefined ? { phaseIterations: resolved.phaseIterations } : {}),\n ...(phases ? { phases } : {}),\n ...(!config.phases ? { iterations: resolved.iterations } : {}),\n concurrency: resolved.concurrency,\n staggerDelayMs: resolved.staggerDelayMs,\n groupBy: resolved.groupBy,\n ...(config.dimensions ? { dimensions: config.dimensions } : {}),\n ...(config.scoring ? { scoring: config.scoring } : {}),\n participants,\n };\n return JSON.parse(JSON.stringify(runConfig)) as JsonObject;\n}\n\n/**\n * Runs `config`'s `task` against its participants. Selects participants by\n * `--provider` (if given), env-gates them, then drives them per the resolved\n * `groupBy`. `--shape` swaps in a declared variant's identity; `--benchmark`/\n * `--name` retarget the run at a different platform benchmark, so one entrypoint\n * can report under several slugs. With `--run-key`, sibling processes (e.g. one\n * CI job per provider) get-or-create one shared run and each registers only its\n * own participants.\n */\nexport async function runBenchmark<T extends BaseParticipant>(\n fileConfig: BenchmarkConfig<T>,\n task: BenchmarkTask<T>,\n argv: string[] = [],\n): Promise<BenchmarkRunOutcome> {\n const args = parseCliArgs(argv, fileConfig.customCliFlags);\n const noIngest = args.noIngest ?? isEnvNoIngest();\n const shaped = applyShape(fileConfig, resolveShape(fileConfig, args.shape));\n const config = applyIdentityOverrides(shaped, args);\n const resolved = mergeConfig(config, args);\n\n const auth = await resolveAuth();\n const client = createBenchmarkClient({\n baseUrl: auth.apiBaseUrl,\n apiKey: auth.apiKey,\n token: auth.token,\n orgSlug: auth.orgSlug,\n orgId: auth.orgId,\n });\n\n const available = resolveParticipants(config, resolved);\n\n const schedule = buildSchedule(config, resolved, task);\n const totalTasks = schedule.length;\n\n const concurrencyLabel = String(resolved.concurrency);\n console.log(`${config.benchmarkName} (self-contained)`);\n console.log(`Date: ${new Date().toISOString()}`);\n if (noIngest) {\n console.log('Dry run: no platform ingest or reporting.\\n');\n }\n console.log(\n `Knobs: iterations=${totalTasks}, concurrency=${concurrencyLabel}, ` +\n `staggerDelayMs=${resolved.staggerDelayMs}, groupBy=${resolved.groupBy}\\n`,\n );\n\n // Declaratively materialize the benchmark from the file/shape identity, which\n // is authoritative (its name lives in the file). A bare `--benchmark X` only\n // *retargets* reporting at a benchmark this file doesn't name, so we don't\n // upsert it — that would rename it to the file's own name.\n const identityIsOurs =\n args.shape !== undefined ||\n args.name !== undefined ||\n !args.benchmark ||\n args.benchmark === fileConfig.benchmarkSlug;\n\n let runId: string;\n let dashboardUrl: string;\n if (noIngest) {\n runId = 'no-ingest';\n dashboardUrl = '';\n } else {\n if (identityIsOurs) {\n const benchmarkConfig: JsonObject = {\n ...(config.scoring ? { scoring: config.scoring as unknown as JsonObject } : {}),\n ...(config.display ? { display: config.display as unknown as JsonObject } : {}),\n };\n await client!.upsertBenchmark(config.benchmarkSlug, {\n name: config.benchmarkName,\n ...(Object.keys(benchmarkConfig).length > 0 ? { config: benchmarkConfig } : {}),\n });\n }\n\n const runConfig = client\n ? runConfigToJson(config, resolved, available.map((p) => p.name))\n : {};\n\n if (args.runKey) {\n // Shared run: get-or-created by key, so sibling processes (one per provider)\n // converge on one run. Opened participant-sized — register only the\n // providers this process runs and let each sibling register its own, so the\n // run lists exactly who's benchmarked and each brings its own task count.\n const { run, organizationSlug } = await client!.createRun(config.benchmarkSlug, {\n runKey: args.runKey,\n config: runConfig,\n });\n runId = run.id;\n dashboardUrl = dashboardUrlFor(auth.apiBaseUrl, organizationSlug, config.benchmarkSlug, run.id);\n for (const participant of available) {\n await client!.upsertParticipant(config.benchmarkSlug, runId, participant.name, { totalTasks });\n }\n console.log(`Shared run (key \"${args.runKey}\"): ${run.name} (${runId})`);\n console.log(`View at: ${dashboardUrl}\\n`);\n } else {\n const { run, organizationSlug } = await client!.createRun(config.benchmarkSlug, {\n totalTasks,\n workerCount: 1,\n participants: available.map((p) => p.name),\n config: runConfig,\n });\n runId = run.id;\n dashboardUrl = dashboardUrlFor(auth.apiBaseUrl, organizationSlug, config.benchmarkSlug, run.id);\n console.log(`Run created: ${run.name} (${runId})`);\n console.log(`View at: ${dashboardUrl}\\n`);\n }\n }\n\n const onResult = defaultOnResult;\n\n let participantRecords: ParticipantRecords[];\n if (resolved.groupBy === 'round') {\n participantRecords = await runGroupedByRound(config, schedule, available, resolved, client, runId, auth.apiBaseUrl, auth.apiKey, auth.token, auth.orgSlug, auth.orgId, onResult, noIngest);\n } else {\n participantRecords = await runGroupedByParticipant(config, schedule, available, resolved, client, runId, onResult, noIngest);\n }\n\n console.log(`All done. ${noIngest ? 'No platform run created.' : `View at: ${dashboardUrl}`}`);\n const outcome: BenchmarkRunOutcome = {\n runId,\n dashboardUrl,\n participants: participantRecords,\n config: resolved,\n };\n if (!noIngest && (config.onScore || config.scoring)) {\n try {\n const spec = config.onScore\n ? await config.onScore(lowerIsBetter, higherIsBetter)\n : scoringConfigToSpec(config.scoring!, config.dimensions, config.display);\n const scored = score(outcome, spec, config.display?.metrics);\n const run = {\n gitSha: process.env.GITHUB_SHA ?? getGitSha(),\n gitRef: process.env.GITHUB_REF_NAME ?? process.env.GITHUB_REF ?? getGitRef(),\n triggeredBy: process.env.GITHUB_EVENT_NAME ?? 'manual',\n nodeVersion: process.version,\n platform: os.platform(),\n arch: os.arch(),\n };\n await client.submitRunSummary(config.benchmarkSlug, runId, {\n run,\n results: scored,\n ...(config.scoring ? { scoring: config.scoring as unknown as JsonObject } : {}),\n });\n } catch (err) {\n // A ScoringSpecError means the scoring spec is misconfigured (e.g. metric\n // weights don't sum to 1.0) — an authoring bug, not a transient submit\n // failure, so it must fail the run rather than degrade to a warning.\n if (err instanceof ScoringSpecError) throw err;\n const message = err instanceof Error ? err.message : String(err);\n console.warn(`[benchsdk-runner] failed to submit run summary: ${message}`);\n }\n }\n if (config.onComplete) await config.onComplete(outcome);\n return outcome;\n}\n\nfunction getGitSha(): string | undefined {\n if (process.env.GITHUB_SHA) return process.env.GITHUB_SHA;\n try {\n return execSync('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();\n } catch {\n return undefined;\n }\n}\n\nfunction getGitRef(): string | undefined {\n if (process.env.GITHUB_REF_NAME) return process.env.GITHUB_REF_NAME;\n if (process.env.GITHUB_REF) return process.env.GITHUB_REF;\n try {\n return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();\n } catch {\n return undefined;\n }\n}\n\n/**\n * 'participant' ordering: one `runWorker` call per participant, in turn.\n * `staggerDelayMs` here launches task N at `workerStart + N * staggerDelayMs`\n * (vs. round mode's fixed delay between rounds — intentionally different).\n * `TaskResult.steps`/`latencyMs` are ignored in this path: the platform\n * worker owns step timing and latency.\n */\nasync function runGroupedByParticipant<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n schedule: Slot<T>[],\n available: T[],\n resolved: ResolvedRunConfig,\n client: BenchmarkClient | null,\n runId: string,\n onResult: OnResult,\n noIngest: boolean,\n): Promise<ParticipantRecords[]> {\n const participantRecords: ParticipantRecords[] = [];\n for (const participant of available) {\n console.log(`${'='.repeat(70)}`);\n console.log(` Participant: ${participant.name}`);\n console.log('='.repeat(70));\n\n // When running without platform ingest, execute the schedule locally.\n if (noIngest || !client) {\n const records: TaskResultRecord[] = [];\n let rampStartMs: number | undefined;\n let nextIndex = 0;\n const logBuffer = new LogBuffer();\n\n const runSlot = async (scheduleIndex: number) => {\n if (resolved.staggerDelayMs > 0) {\n rampStartMs ??= Date.now();\n const waitMs = rampStartMs + scheduleIndex * resolved.staggerDelayMs - Date.now();\n if (waitMs > 0) await sleep(waitMs);\n }\n const slot = schedule[scheduleIndex];\n const record = await runTaskRecord(slot.task, participant, scheduleIndex, scheduleIndex, slot.phase, logBuffer);\n onResult(record, { iterations: schedule.length, participant: participant.name });\n records.push(record);\n };\n\n const worker = async () => {\n while (nextIndex < schedule.length) {\n const index = nextIndex++;\n await runSlot(index);\n }\n };\n\n await Promise.all(Array.from({ length: resolved.concurrency }, () => worker()));\n records.sort((a, b) => a.taskIndex - b.taskIndex);\n\n const ok = records.filter((r) => r.status === 'success').length;\n console.log(` Done: ${ok}/${records.length} succeeded.\\n`);\n participantRecords.push({ participant: participant.name, records });\n continue;\n }\n\n // Anchors the ramp to the worker's start, so a pool narrower than the task\n // count can't inflate launch offsets: a task whose slot frees after its\n // scheduled launch time starts immediately instead of sleeping index*delay.\n let rampStartMs: number | undefined;\n await client.planWorkers(config.benchmarkSlug, runId, participant.name);\n\n const result = await runWorker(client, {\n benchmarkSlug: config.benchmarkSlug,\n runId: runId,\n participantSlug: participant.name,\n concurrency: resolved.concurrency,\n task: async (ctx: RunWorkerContext) => {\n // `ctx.taskIndex` is the platform's global index; the schedule is\n // indexed from the worker's own task range start.\n const scheduleIndex = ctx.taskIndex - ctx.assignment.taskRange.start;\n if (resolved.staggerDelayMs > 0) {\n rampStartMs ??= Date.now();\n const waitMs = rampStartMs + scheduleIndex * resolved.staggerDelayMs - Date.now();\n if (waitMs > 0) await sleep(waitMs);\n }\n const slot = schedule[scheduleIndex];\n // The client owns step timing, `measure` attribution, and worker-log\n // upload; the runner just threads them onto the task context. The runner\n // wraps `ctx.step` so per-step `timeoutMs` and `concurrency` work in\n // participant mode as well.\n // Tagged before the task runs, not after: measures survive a thrown\n // task, so a failed record still carries its phase and can be grouped\n // (and filtered) alongside the successful records of that phase.\n if (slot.phase) ctx.measure({ phase: slot.phase });\n try {\n const taskResult = await slot.task({\n participant,\n taskIndex: scheduleIndex,\n phase: slot.phase,\n step: (name, fn, options) => runStepWithClient(ctx.step, name, fn, options),\n measure: ctx.measure,\n log: ctx.log,\n });\n return taskResult?.data;\n } catch (error) {\n // Mirrors the 'round' path: a TaskError's domain data is preserved on\n // the failure record instead of being dropped for the error message.\n if (isTaskError(error) && error.data) ctx.measure(error.data);\n throw error;\n }\n },\n onResult: (record) => onResult(record, { iterations: schedule.length, participant: participant.name }),\n });\n\n if (!result.assignment) {\n console.error(` No pending worker to claim for run ${runId} — it may already be fully claimed.`);\n participantRecords.push({ participant: participant.name, records: result.records ?? [] });\n continue;\n }\n\n const ok = result.records.filter((r) => r.status === 'success').length;\n console.log(` Done: ${ok}/${result.records.length} succeeded.\\n`);\n participantRecords.push({ participant: participant.name, records: result.records });\n }\n\n return participantRecords;\n}\n\n/**\n * 'round' ordering: claim one `BenchmarkReporter` per participant up front,\n * then loop rounds, running one task per participant per round and streaming\n * each result to its reporter. Steps are built manually (no `runWorker`\n * to own them) via a shim that mirrors the platform's record shape.\n */\nasync function runGroupedByRound<T extends BaseParticipant>(\n config: BenchmarkConfig<T>,\n schedule: Slot<T>[],\n available: T[],\n resolved: ResolvedRunConfig,\n client: BenchmarkClient | null,\n runId: string,\n baseUrl: string,\n apiKey: string | undefined,\n token: string | undefined,\n orgSlug: string | undefined,\n orgId: string | undefined,\n onResult: OnResult,\n noIngest: boolean = false,\n): Promise<ParticipantRecords[]> {\n const reporters = new Map<string, BenchmarkReporter | null>();\n const logBuffers = new Map<string, LogBuffer>();\n const failed = new Map<string, boolean>();\n const recordsByParticipant = new Map<string, TaskResultRecord[]>();\n // A single collector for the whole run: round mode interleaves every\n // participant in this one shared Node process, so per-participant CPU/memory\n // can't be isolated — a sample reflects the whole process, not one slice of\n // it. We therefore sample once per round (not once per participant) and\n // upload a single `system-metrics` artifact, rather than N duplicates that\n // would falsely imply isolated per-participant usage. (Separate artifacts\n // only make sense when workers genuinely run on separate VMs, one per\n // participant, as the client `runWorker` path does.) Created only when at\n // least one participant has a reporter to upload to — nothing else reads it.\n let metricsCollector: BenchmarkSystemMetricsCollector | undefined;\n const metricsSamples: BenchmarkSystemMetricsSample[] = [];\n\n for (const participant of available) {\n logBuffers.set(participant.name, new LogBuffer());\n failed.set(participant.name, false);\n recordsByParticipant.set(participant.name, []);\n if (noIngest || !client) {\n reporters.set(participant.name, null);\n continue;\n }\n // One worker per participant drives every round sequentially. The platform\n // reads `targetConcurrency` as tasks-per-worker, so it must be the full\n // schedule length — otherwise only one task is planned and every record\n // past the first falls outside the worker's task range.\n await client.planWorkers(config.benchmarkSlug, runId, participant.name, {\n workerCount: 1,\n targetConcurrency: schedule.length,\n });\n let reporter: BenchmarkReporter | null = null;\n try {\n reporter = await BenchmarkReporter.claim({\n baseUrl,\n apiKey,\n token,\n orgSlug,\n orgId,\n benchmarkSlug: config.benchmarkSlug,\n runId: runId,\n participantSlug: participant.name,\n processKind: 'process',\n processKey: process.env.HOSTNAME ?? 'local',\n });\n } catch (error) {\n console.warn(` ${participant.name}: reporter claim failed (${error instanceof Error ? error.message : String(error)}) — running without platform reporting.`);\n }\n if (!reporter) {\n console.warn(` ${participant.name}: could not claim a platform worker — running without platform reporting.`);\n }\n reporters.set(participant.name, reporter);\n // First reporter to appear starts the one shared collector, with an\n // immediate baseline sample so a run that finishes inside one round still\n // uploads metrics.\n if (reporter && !metricsCollector) {\n metricsCollector = createSystemMetricsCollector();\n metricsSamples.push(await metricsCollector.sample());\n }\n }\n\n console.log(`Interleaving ${available.length} participant(s), ${schedule.length} round(s) each.\\n`);\n\n for (let i = 0; i < schedule.length; i++) {\n const slot = schedule[i];\n // Round mode staggers a fixed delay between rounds (vs. participant mode's per-task stagger).\n if (resolved.staggerDelayMs > 0 && i > 0) {\n await sleep(resolved.staggerDelayMs);\n }\n const roundFns = available.map((participant) => async () => {\n const reporter = reporters.get(participant.name) ?? null;\n const logBuffer = logBuffers.get(participant.name)!;\n const record = await runTaskRecord(\n slot.task,\n participant,\n i,\n (reporter?.taskIndexStart ?? 0) + i,\n slot.phase,\n logBuffer,\n );\n if (record.status !== 'success') failed.set(participant.name, true);\n onResult(record, { iterations: schedule.length, participant: participant.name });\n reporter?.recordResult(record);\n const participantRecords = recordsByParticipant.get(participant.name)!;\n participantRecords.push(record);\n // Round mode drives the worker by hand, so nothing reports progress\n // unless we do: without this the platform shows 0 done for the whole run.\n if (reporter) {\n reporter.setProgress({\n done: participantRecords.length,\n inFlight: 0,\n errors: participantRecords.filter((item) => item.status !== 'success').length,\n total: schedule.length,\n });\n await reporter.heartbeat();\n }\n });\n await runWithConcurrency(roundFns, resolved.concurrency);\n // Sampled once per round rather than on a wall-clock timer: round mode runs\n // everything sequentially in this one loop, so a round boundary is the\n // natural, already-existing cadence. Taken after the whole round (not per\n // participant) since the sample covers the shared process, not one slice.\n if (metricsCollector) metricsSamples.push(await metricsCollector.sample());\n }\n\n // One shared collector for the whole process — a final sample (before stop,\n // which disables the event-loop monitor), then upload a single\n // `system-metrics` artifact via any one reporter (all participants ran in\n // this process, so the metrics belong to the run, not to any one of them).\n if (metricsCollector) metricsSamples.push(await metricsCollector.sample());\n metricsCollector?.stop();\n // The SDK only has a worker-scoped artifact API, so this single artifact is\n // necessarily filed under one reporter's worker. Tag it as process-scoped\n // with the full participant list so consumers don't mistake it for that one\n // participant's isolated usage — the metrics cover every participant that ran\n // in this shared process, not just the reporter it happened to upload through.\n const metricsReporter = available.map((p) => reporters.get(p.name)).find((r): r is BenchmarkReporter => Boolean(r));\n if (metricsReporter && metricsSamples.length > 0) {\n await metricsReporter\n .uploadArtifact({\n kind: 'system-metrics',\n contentType: 'application/x-ndjson',\n name: 'metrics.jsonl',\n metadata: { scope: 'shared-process', participants: available.map((p) => p.name) },\n body: metricsSamples.map((sample) => JSON.stringify(sample)).join('\\n') + '\\n',\n })\n .catch(() => {});\n }\n\n for (const participant of available) {\n const reporter = reporters.get(participant.name) ?? null;\n const logBuffer = logBuffers.get(participant.name)!;\n if (reporter && !logBuffer.isEmpty()) {\n await reporter\n .uploadArtifact({ kind: 'coordinator.log', contentType: 'text/plain', name: 'worker.log', body: logBuffer.toText() })\n .catch(() => {});\n }\n await reporter?.finish(failed.get(participant.name) ?? false);\n console.log(` ${participant.name}: done${failed.get(participant.name) ? ' (with errors)' : ''}.`);\n }\n\n return available.map((p) => ({ participant: p.name, records: recordsByParticipant.get(p.name) ?? [] }));\n}\n\n/** Merges a task's data payload with the current phase tag (if any). */\nfunction mergeData(data: JsonObject | undefined, phase: string | undefined): JsonObject | undefined {\n const merged = { ...(data ?? {}), ...(phase ? { phase } : {}) };\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\n/**\n * Runs one task for the manual 'round' path, building its `TaskResultRecord`.\n * Honors the full `TaskResult` (task-owned data/steps/latency) and `TaskError`\n * (preserves domain data + steps on failure). Framework-timed `ctx.step` calls\n * and task-owned `result.steps` are both recorded.\n */\nasync function runTaskRecord<T extends BaseParticipant>(\n task: BenchmarkTask<T>,\n participant: T,\n scheduleIndex: number,\n taskIndex: number,\n phase: string | undefined,\n logBuffer: LogBuffer,\n): Promise<TaskResultRecord> {\n const startedAtMs = Date.now();\n const record: TaskResultRecord = {\n taskIndex,\n status: 'success',\n startedAt: new Date(startedAtMs).toISOString(),\n };\n const frameworkSteps: TaskStepRecord[] = [];\n const taskMeasures: JsonObject = {};\n // Mirrors the client worker: `measure` lands on the active step (if any),\n // else on task-level measurements folded into `record.data`.\n let activeStep: TaskStepRecord | null = null;\n\n const ctx: TaskContext<T> = {\n participant,\n taskIndex: scheduleIndex,\n phase,\n async step<R, C extends number = 1>(\n name: string,\n fn: () => Promise<R> | R,\n options?: TaskStepOptions & { concurrency?: C },\n ): Promise<C extends 1 ? R : R[]> {\n const stepStartedAtMs = Date.now();\n const stepRecord: TaskStepRecord = {\n name,\n status: 'success',\n startedAt: new Date(stepStartedAtMs).toISOString(),\n completedAt: new Date(stepStartedAtMs).toISOString(),\n latencyMs: 0,\n };\n if (options?.concurrency !== undefined) stepRecord.concurrency = options.concurrency;\n if (options?.timeoutMs !== undefined) stepRecord.timeoutMs = options.timeoutMs;\n const previousStep = activeStep;\n activeStep = stepRecord;\n try {\n const result = await runStepInvocations<R>(name, fn, options);\n const outcome: BenchmarkStepOutcome =\n options?.captureOutput !== false && !Array.isArray(result) && isStepOutcome(result)\n ? (result as BenchmarkStepOutcome)\n : {};\n logBuffer.step(taskIndex, name, outcome);\n return result as C extends 1 ? R : R[];\n } catch (error) {\n stepRecord.status = 'error';\n stepRecord.errorCode = isTaskError(error) ? error.code ?? error.name : getErrorCode(error);\n logBuffer.step(taskIndex, name, { error: error instanceof Error ? error.message : String(error) });\n throw error;\n } finally {\n activeStep = previousStep;\n stepRecord.completedAt = new Date().toISOString();\n stepRecord.latencyMs = Date.now() - stepStartedAtMs;\n frameworkSteps.push(stepRecord);\n }\n },\n measure(data) {\n if (activeStep) {\n activeStep.data = { ...(activeStep.data ?? {}), ...data };\n } else {\n Object.assign(taskMeasures, data);\n }\n },\n log(message, metaOrOptions) {\n logBuffer.line(`[task ${taskIndex}] ${message}`, metaOrOptions);\n },\n };\n\n let result: TaskResult | void = undefined;\n try {\n result = await task(ctx);\n record.data = mergeData({ ...taskMeasures, ...(result?.data ?? {}) }, phase);\n } catch (error) {\n record.status = 'error';\n if (isTaskError(error)) {\n record.errorCode = error.code ?? error.name;\n record.data = mergeData({ ...taskMeasures, ...(error.data ?? {}) }, phase);\n if (error.steps?.length) frameworkSteps.push(...error.steps);\n } else {\n record.errorCode = getErrorCode(error);\n record.data = mergeData(\n { ...taskMeasures, errorMessage: error instanceof Error ? error.message : String(error) },\n phase,\n );\n }\n } finally {\n const endMs = Date.now();\n record.completedAt = new Date(endMs).toISOString();\n record.latencyMs =\n record.status === 'success' && result && typeof result.latencyMs === 'number'\n ? result.latencyMs\n : endMs - startedAtMs;\n const taskSteps = record.status === 'success' && result?.steps ? result.steps : [];\n const allSteps = [...frameworkSteps, ...taskSteps];\n // A task that declared no steps is recorded as a single implicit 'task'\n // step, matching the client worker's behavior.\n if (allSteps.length === 0) {\n allSteps.push({\n name: 'task',\n status: record.status === 'success' ? 'success' : 'error',\n startedAt: record.startedAt,\n completedAt: record.completedAt,\n latencyMs: record.latencyMs,\n errorCode: record.errorCode ?? null,\n data: Object.keys(taskMeasures).length > 0 ? { ...taskMeasures } : undefined,\n });\n }\n record.steps = allSteps;\n }\n\n return record;\n}\n","import type { JsonObject, TaskResultRecord } from '@benchsdk/api';\nimport type { BenchmarkRunOutcome } from './bench-config.js';\n\nexport type MetricValue = string | ((record: TaskResultRecord) => number | number[] | undefined);\n\nexport interface MetricScoring {\n name: string;\n value?: MetricValue;\n unit?: string;\n ceiling: number;\n floor?: number;\n higherIsBetter?: boolean;\n weights: { median: number; p95: number; p99: number };\n trim?: number;\n}\n\nexport interface BenchmarkScoringWeights {\n median: number;\n p95: number;\n p99: number;\n}\n\nexport interface BenchmarkScoringMetric {\n key: string;\n label?: string;\n unit?: string;\n ceiling: number;\n floor?: number;\n higherIsBetter?: boolean;\n weights: BenchmarkScoringWeights;\n trim?: number;\n}\n\n/**\n * Serializable counterpart to a `success` predicate: a record counts as\n * successful only if it succeeded *and* every listed data field equals the\n * given value (e.g. `{ verified: true }`, `{ actionsCompleted: 24 }`). Kept to\n * equality on scalar data fields so the platform can express the same rule as\n * a query predicate rather than replaying benchmark code.\n */\nexport interface BenchmarkScoringSuccess {\n requireData: Record<string, string | number | boolean>;\n}\n\n/** Serializable scoring spec declared in a `*.bench.ts` file and uploaded to the platform. */\nexport interface BenchmarkScoringConfig {\n /** Optional data key to group records by when computing summary rows (e.g. 'file_size'). */\n groupBy?: string;\n /** Extra conditions a record must meet to count as successful. Default: `status === 'success'`. */\n success?: BenchmarkScoringSuccess;\n metrics: BenchmarkScoringMetric[];\n}\n\nexport interface ScoringSpec {\n dimensions?: Record<string, unknown>;\n /** Optional data key that groups task records into separate summary rows. */\n groupBy?: string;\n success?: (record: TaskResultRecord) => boolean;\n metrics: MetricScoring[];\n}\n\nexport interface BenchmarkScoreResult {\n provider: string;\n dimensions: JsonObject;\n metrics: { name: string; unit: string; median: number; p95: number; p99: number }[];\n scalars?: { name: string; value: number; unit: string }[];\n compositeScore: number;\n successRate: number;\n scoringVersion?: string;\n skipped: boolean;\n skipReason?: string;\n}\n\nexport type LowerIsBetter = (\n name: string,\n opts: {\n unit?: string;\n ceiling: number;\n value?: MetricValue;\n weights: { median: number; p95: number; p99: number };\n trim?: number;\n },\n) => MetricScoring;\n\nexport type HigherIsBetter = (\n name: string,\n opts: {\n unit?: string;\n floor?: number;\n ceiling: number;\n value?: MetricValue;\n weights: { median: number; p95: number; p99: number };\n trim?: number;\n },\n) => MetricScoring;\n\nfunction isFiniteNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v);\n}\n\nfunction percentile(sorted: number[], p: number): number {\n if (sorted.length === 0) return 0;\n const idx = Math.max(0, Math.ceil((p / 100) * sorted.length) - 1);\n return sorted[Math.min(idx, sorted.length - 1)];\n}\n\nfunction computeStats(values: number[], trimPercent: number = 0.05): { median: number; p95: number; p99: number } {\n if (values.length === 0) return { median: 0, p95: 0, p99: 0 };\n\n const sorted = [...values].sort((a, b) => a - b);\n\n const trimCount = Math.floor(sorted.length * trimPercent);\n const trimmed = trimCount > 0 && sorted.length - 2 * trimCount > 0\n ? sorted.slice(trimCount, sorted.length - trimCount)\n : sorted;\n\n const mid = Math.floor(trimmed.length / 2);\n const median = trimmed.length % 2 === 0\n ? (trimmed[mid - 1] + trimmed[mid]) / 2\n : trimmed[mid];\n\n return { median, p95: percentile(trimmed, 95), p99: percentile(trimmed, 99) };\n}\n\nfunction toJsonObject(value: Record<string, unknown>): JsonObject {\n return JSON.parse(JSON.stringify(value ?? {})) as JsonObject;\n}\n\nfunction collectSamples(metric: MetricScoring, records: TaskResultRecord[]): number[] {\n const samples: number[] = [];\n for (const record of records) {\n const raw = typeof metric.value === 'function'\n ? metric.value(record)\n : record.data?.[metric.value ?? metric.name];\n\n if (Array.isArray(raw)) {\n for (const item of raw) {\n if (isFiniteNumber(item)) samples.push(item);\n }\n } else if (isFiniteNumber(raw)) {\n samples.push(raw);\n }\n }\n return samples;\n}\n\nfunction scoreStat(stat: number, metric: MetricScoring): number {\n if (metric.higherIsBetter) {\n const floor = metric.floor ?? 0;\n if (stat <= floor) return 0;\n if (stat >= metric.ceiling) return 100;\n return ((stat - floor) / (metric.ceiling - floor)) * 100;\n }\n return Math.max(0, 100 * (1 - stat / metric.ceiling));\n}\n\nexport const lowerIsBetter: LowerIsBetter = (name, opts) => ({\n name,\n ...opts,\n higherIsBetter: false,\n});\n\nexport const higherIsBetter: HigherIsBetter = (name, opts) => ({\n name,\n ...opts,\n higherIsBetter: true,\n});\n\nconst WEIGHT_SUM_TOLERANCE = 0.01;\n\n// Thrown by validateScoringSpec — a distinguishable type so runner.ts can\n// tell \"this benchmark's onScore is misconfigured\" (an authoring bug, must\n// fail the run) apart from transient submit/network failures (which should\n// keep degrading to a warning, per runner.ts's existing catch behavior).\nexport class ScoringSpecError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ScoringSpecError';\n }\n}\n\n// Each metric's weights.median + weights.p95 + weights.p99 is a share of the\n// overall 0-100 compositeScore — summed across every declared metric they\n// must total 1.0, or compositeScore silently drifts off its advertised\n// scale. Validated against spec.metrics as declared, not the post-sample-\n// filter scores in score()'s participant loop, since a metric with zero\n// samples for a given participant is legitimately excluded there — a\n// per-run runtime fact, not an authoring mistake.\nexport function validateScoringSpec(spec: ScoringSpec): void {\n const totalWeight = spec.metrics.reduce(\n (sum, m) => sum + m.weights.median + m.weights.p95 + m.weights.p99,\n 0,\n );\n if (Math.abs(totalWeight - 1) > WEIGHT_SUM_TOLERANCE) {\n const breakdown = spec.metrics\n .map((m) => `${m.name}=${(m.weights.median + m.weights.p95 + m.weights.p99).toFixed(3)}`)\n .join(', ');\n throw new ScoringSpecError(\n `Scoring spec weights sum to ${totalWeight.toFixed(3)}, expected 1.0 ` +\n `(±${WEIGHT_SUM_TOLERANCE}). Each metric's weights.median + weights.p95 + weights.p99, ` +\n `summed across every declared metric, must total 1.0 for compositeScore to stay a ` +\n `meaningful 0-100 scale. Per-metric totals: ${breakdown || '(no metrics declared)'}`,\n );\n }\n}\n\nfunction groupRecordsByKey(\n records: TaskResultRecord[],\n key: string,\n): { value: unknown; records: TaskResultRecord[] }[] {\n const groups = new Map<string, { value: unknown; records: TaskResultRecord[] }>();\n for (const record of records) {\n const raw = record.data?.[key];\n const value = raw === undefined ? undefined : raw;\n const mapKey = value === undefined ? '__undefined__' : JSON.stringify(value);\n let group = groups.get(mapKey);\n if (!group) {\n group = { value, records: [] };\n groups.set(mapKey, group);\n }\n group.records.push(record);\n }\n return Array.from(groups.values());\n}\n\nfunction scoreGroup(\n records: TaskResultRecord[],\n spec: ScoringSpec,\n baseDimensions: JsonObject,\n groupKey: string | undefined,\n groupValue: unknown,\n provider: string,\n unitByMetric: Map<string, string | undefined>,\n): BenchmarkScoreResult {\n const successFilter = spec.success ?? ((r: TaskResultRecord) => r.status === 'success');\n const passing = records.filter(successFilter);\n const successRate = records.length === 0 ? 0 : passing.length / records.length;\n const skipped = records.length === 0;\n\n let metricScoresSum = 0;\n const metrics: BenchmarkScoreResult['metrics'] = [];\n\n for (const metric of spec.metrics) {\n const samples = collectSamples(metric, passing);\n // A metric with no data points should not contribute to the composite\n // score; otherwise an empty lower-is-better metric would be scored as 100.\n if (samples.length === 0) {\n continue;\n }\n const { median, p95, p99 } = computeStats(samples, metric.trim ?? 0.05);\n const metricScore =\n metric.weights.median * scoreStat(median, metric) +\n metric.weights.p95 * scoreStat(p95, metric) +\n metric.weights.p99 * scoreStat(p99, metric);\n metricScoresSum += metricScore;\n\n const unitKey = typeof metric.value === 'string' ? metric.value : metric.name;\n const unit = metric.unit ?? unitByMetric.get(unitKey) ?? '';\n metrics.push({ name: metric.name, unit, median, p95, p99 });\n }\n\n const compositeScore = successRate === 0 ? 0 : Math.round(metricScoresSum * successRate * 100) / 100;\n\n const dimensions = toJsonObject({\n ...baseDimensions,\n ...(groupKey !== undefined && groupValue !== undefined ? { [groupKey]: groupValue } : {}),\n });\n\n return {\n provider,\n dimensions,\n metrics,\n compositeScore,\n successRate,\n skipped,\n };\n}\n\nexport function score(\n outcome: BenchmarkRunOutcome,\n spec: ScoringSpec,\n displayMetrics?: { key: string; unit?: string }[],\n): BenchmarkScoreResult[] {\n validateScoringSpec(spec);\n const baseDimensions = toJsonObject(spec.dimensions ?? {});\n const unitByMetric = new Map(displayMetrics?.map((m) => [m.key, m.unit]));\n const results: BenchmarkScoreResult[] = [];\n\n for (const { participant, records } of outcome.participants) {\n // A participant that recorded nothing has no group to belong to, but it\n // still has to appear in the summary as skipped rather than vanish from it.\n const groups = spec.groupBy && records.length > 0\n ? [{ value: undefined, records }, ...groupRecordsByKey(records, spec.groupBy)]\n : [{ value: undefined, records }];\n\n for (const group of groups) {\n results.push(scoreGroup(group.records, spec, baseDimensions, spec.groupBy, group.value, participant, unitByMetric));\n }\n }\n\n return results;\n}\n\n/** Builds a runtime {@link ScoringSpec} from a serializable {@link BenchmarkScoringConfig}. */\nexport function scoringConfigToSpec(\n config: BenchmarkScoringConfig,\n dimensions?: Record<string, unknown>,\n display?: { metrics?: { key: string; unit?: string }[] },\n): ScoringSpec {\n const success = config.success;\n const unitByMetric = new Map(display?.metrics?.map((m) => [m.key, m.unit]));\n return {\n ...(dimensions ? { dimensions: toJsonObject(dimensions) } : {}),\n ...(config.groupBy ? { groupBy: config.groupBy } : {}),\n ...(success\n ? {\n success: (record: TaskResultRecord) =>\n record.status === 'success' &&\n Object.entries(success.requireData).every(([key, value]) => record.data?.[key] === value),\n }\n : {}),\n metrics: config.metrics.map((metric) => ({\n name: metric.key,\n value: metric.key,\n unit: (display?.metrics === undefined ? metric.unit : (unitByMetric.get(metric.key) ?? metric.unit)) ?? '',\n ceiling: metric.ceiling,\n floor: metric.floor,\n higherIsBetter: metric.higherIsBetter,\n weights: metric.weights,\n trim: metric.trim,\n })),\n };\n}\n","import type { BenchmarkLogLevel, BenchmarkLogOptions, BenchmarkStepOutcome } from '@benchsdk/api';\n\n/**\n * Accumulates one text log per worker across a task's steps, uploaded once as a\n * `coordinator.log` artifact. Used by the runner's manual `round` mode, where\n * `client.runWorker` (which owns log upload in `participant` mode) is not in\n * play.\n */\nexport type StepOutcome = BenchmarkStepOutcome;\n\nconst LOG_LEVEL_ORDER: BenchmarkLogLevel[] = ['debug', 'info', 'warn', 'error'];\n\nfunction isLogOptions(value: unknown): value is BenchmarkLogOptions {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const o = value as Record<string, unknown>;\n const keys = Object.keys(o);\n if (keys.length === 0) return false;\n if (!keys.every((k) => k === 'level' || k === 'meta')) return false;\n if (o.level !== undefined && (typeof o.level !== 'string' || !LOG_LEVEL_ORDER.includes(o.level as BenchmarkLogLevel))) {\n return false;\n }\n return true;\n}\n\nexport class LogBuffer {\n private readonly lines: string[] = [];\n\n step(taskIndex: number, stepName: string, outcome: BenchmarkStepOutcome): void {\n const header = `[task ${taskIndex}] ${stepName}`;\n this.lines.push(`${new Date().toISOString()} ${header}`);\n if (outcome.stdout?.trim()) {\n this.lines.push(indent(outcome.stdout));\n }\n if (outcome.stderr?.trim()) {\n this.lines.push(indent(outcome.stderr, 'stderr: '));\n }\n if (outcome.error) {\n this.lines.push(indent(outcome.error, 'error: '));\n }\n }\n\n /** Appends a free-form narration line (backs the task context's `log`). */\n line(message: string, metaOrOptions?: Record<string, unknown> | BenchmarkLogOptions): void {\n const opts: { level: BenchmarkLogLevel; meta?: Record<string, unknown> } = isLogOptions(metaOrOptions)\n ? { level: metaOrOptions.level ?? 'info', meta: metaOrOptions.meta }\n : { level: 'info', meta: metaOrOptions };\n const suffix = opts.meta && Object.keys(opts.meta).length > 0 ? ` ${JSON.stringify(opts.meta)}` : '';\n // The runner's ctx.log passes a leading `[task N]` prefix; place the level\n // between the task tag and the message to match `@benchsdk/worker` and the\n // platform's worker-logs parser.\n const taskMatch = message.match(/^(\\[task \\d+\\])\\s*(.*)$/);\n if (taskMatch) {\n this.lines.push(`${new Date().toISOString()} ${taskMatch[1]} [${opts.level}] ${taskMatch[2]}${suffix}`);\n } else {\n this.lines.push(`${new Date().toISOString()} [${opts.level}] ${message}${suffix}`);\n }\n }\n\n isEmpty(): boolean {\n return this.lines.length === 0;\n }\n\n toText(): string {\n return this.lines.join('\\n') + '\\n';\n }\n}\n\nfunction indent(text: string, prefix = ''): string {\n return text\n .trimEnd()\n .split('\\n')\n .map((line) => ` ${prefix}${line}`)\n .join('\\n');\n}\n","/**\n * The author-facing entrypoint. `bench` is verbs-only — the benchmark and its\n * runs are implicit, never nouns you type:\n *\n * bench run <file.bench.ts> [--flags] execute a benchmark\n *\n * `run` imports a benchmark module, reads its `config` and `task` exports and\n * drives `runBenchmark`; CLI flags override the config's knobs and\n * `config.onComplete` (if any) fires once the run finishes. The benchmark is\n * declared in the file (`--shape` picks a named variant) and materialized on\n * run; a run is opened as a side effect, shared across sibling processes when\n * they pass the same `--run-key`. There are no imperative `create` commands.\n *\n * The executable wrapper lives in `bin.ts`; this module has no side effects so\n * it can be unit-tested by calling `runBenchmarkFile` directly.\n */\nimport { resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { run as runPlatformCli } from '@benchsdk/cli';\nimport { parseCliArgs, runBenchmark } from './runner.js';\nimport { NoAvailableParticipantsError } from './no-available-participants.js';\nimport type { BaseParticipant } from '@benchsdk/worker';\nimport type { BenchmarkConfig, BenchmarkTask } from './bench-config.js';\n\nconst USAGE =\n 'Usage:\\n' +\n ' bench run <file.bench.ts> [--shape name] [--provider a,b] [--run-key key]\\n' +\n ' [--benchmark slug] [--name \"My benchmark\"]\\n' +\n ' [--iterations N] [--concurrency N] [--stagger-delay-ms N] [--group-by participant|round]\\n' +\n ' [--no-ingest | --dry-run]';\n\n/** A benchmark module is expected to export `config` and `task`. */\ninterface BenchmarkModule {\n config?: unknown;\n task?: unknown;\n default?: unknown;\n}\n\nfunction isBenchmarkConfig(value: unknown): value is BenchmarkConfig {\n if (typeof value !== 'object' || value === null) return false;\n const candidate = value as { benchmarkSlug?: unknown; participants?: unknown };\n return typeof candidate.benchmarkSlug === 'string' && Array.isArray(candidate.participants);\n}\n\n/**\n * Dispatches one CLI invocation. Throws on bad usage / invalid exports and lets\n * `NoAvailableParticipantsError` propagate so the caller can map it to a clean\n * exit. Does not call `process.exit`.\n */\nexport async function runBenchmarkFile(argv: string[]): Promise<void> {\n const [command, ...rest] = argv;\n\n const [file, ...flags] = rest;\n if (command !== 'run' || !file || file.startsWith('-')) throw new Error(USAGE);\n\n const mod = (await import(pathToFileURL(resolve(process.cwd(), file)).href)) as BenchmarkModule;\n const config = mod.config;\n const task = mod.task ?? mod.default;\n\n if (!isBenchmarkConfig(config)) {\n throw new Error(`${file} must export a \\`config\\` created with defineBenchmarkConfig (with participants).`);\n }\n if (typeof task !== 'function') {\n throw new Error(`${file} must export a \\`task\\` created with defineTask.`);\n }\n\n await runBenchmark(config as BenchmarkConfig<BaseParticipant>, task as BenchmarkTask<BaseParticipant>, flags);\n}\n\n/** Executable entry: dispatches to benchmark execution or platform data commands. */\nexport async function run(argv: string[]): Promise<void> {\n if (argv[0] !== 'run') {\n return runPlatformCli(argv);\n }\n\n try {\n await runBenchmarkFile(argv);\n // Provider SDKs can leave sockets/timers open; exit explicitly so a\n // finished run doesn't hang.\n process.exit(0);\n } catch (err) {\n if (err instanceof NoAvailableParticipantsError) {\n console.log(err.message);\n process.exit(0);\n }\n console.error('Benchmark failed:', err instanceof Error ? err.message : err);\n process.exit(1);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC6FO,IAAM,YAAN,cAAwB,MAAM;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY,SAAiB,MAAuE;AAClG,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO,MAAM;AAClB,SAAK,OAAO,MAAM;AAClB,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;AA0NA,SAAS,qBAAqB,OAAgB,OAAuB;AACnE,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,MAAM,IAAI;AACpD,UAAM,IAAI,MAAM,GAAG,KAAK,6BAA6B;AAAA,EACvD;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,OAAgC,SAA4B,OAAqB;AAC9G,aAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,QAAI,CAAC,QAAQ,SAAS,GAAG,GAAG;AAC1B,YAAM,IAAI,MAAM,GAAG,KAAK,8BAA8B,GAAG,GAAG;AAAA,IAC9D;AAAA,EACF;AACF;AAEA,SAAS,kBAAkB,OAA2B,OAAqB;AACzE,MAAI,UAAU,OAAW;AACzB,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GAAG;AACzC,UAAM,IAAI,MAAM,GAAG,KAAK,iCAAiC,KAAK,GAAG;AAAA,EACnE;AACF;AAEA,SAAS,mBAAmB,OAAgB,OAAuB;AACjE,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG;AACxD,UAAM,IAAI,MAAM,GAAG,KAAK,iCAAiC,KAAK,GAAG;AAAA,EACnE;AACA,SAAO;AACT;AAEA,SAAS,+BAA+B,SAAiC,SAAwC;AAC/G,MAAI,CAAC,MAAM,QAAQ,QAAQ,OAAO,KAAK,QAAQ,QAAQ,WAAW,GAAG;AACnE,UAAM,IAAI,MAAM,2CAA2C;AAAA,EAC7D;AACA,MAAI,QAAQ,YAAY,QAAW;AACjC,UAAM,cAAc,QAAQ,QAAQ;AACpC,QAAI,gBAAgB,QAAQ,OAAO,gBAAgB,YAAY,MAAM,QAAQ,WAAW,GAAG;AACzF,YAAM,IAAI,MAAM,oDAAoD;AAAA,IACtE;AACA,QAAI,OAAO,KAAK,WAAW,EAAE,WAAW,GAAG;AACzC,YAAM,IAAI,MAAM,kEAAkE;AAAA,IACpF;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,WAAW,GAAG;AACtD,YAAM,OAAO,OAAO;AACpB,UAAI,SAAS,YAAY,SAAS,YAAY,SAAS,WAAW;AAChE,cAAM,IAAI;AAAA,UACR,+BAA+B,GAAG,8CAA8C,IAAI;AAAA,QACtF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,OAAO,oBAAI,IAAY;AAC7B,MAAI,cAAc;AAClB,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,QAAQ,KAAK;AAC/C,UAAM,SAAS,QAAQ,QAAQ,CAAC;AAChC,QAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAC1E,YAAM,IAAI,MAAM,mBAAmB,CAAC,qBAAqB;AAAA,IAC3D;AACA,UAAM,MAAM,OAAO;AACnB,QAAI,OAAO,QAAQ,YAAY,IAAI,KAAK,MAAM,IAAI;AAChD,YAAM,IAAI,MAAM,mBAAmB,CAAC,kCAAkC;AAAA,IACxE;AACA,QAAI,KAAK,IAAI,GAAG,GAAG;AACjB,YAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AAAA,IACxD;AACA,SAAK,IAAI,GAAG;AAGZ,UAAM,iBAAiB,MAAM,QAAQ,SAAS,OAAO,IAAI,QAAS,UAAU;AAC5E,UAAM,gBAAgB,gBAAgB,KAAK,CAAC,MAAM,GAAG,QAAQ,GAAG;AAChE,QAAI,OAAO,SAAS,QAAW;AAC7B,UAAI,OAAO,OAAO,SAAS,UAAU;AACnC,cAAM,IAAI,MAAM,mBAAmB,CAAC,yBAAyB;AAAA,MAC/D;AACA,UAAI,eAAe,SAAS,UAAa,OAAO,SAAS,cAAc,MAAM;AAC3E,cAAM,IAAI;AAAA,UACR,mBAAmB,CAAC,WAAW,OAAO,IAAI,oCAAoC,CAAC,WAAW,cAAc,IAAI,cAAc,GAAG;AAAA,QAC/H;AAAA,MACF;AAAA,IACF;AACA,uBAAmB,OAAO,SAAS,mBAAmB,CAAC,WAAW;AAClE,QAAI,OAAO,UAAU,QAAW;AAC9B,yBAAmB,OAAO,OAAO,mBAAmB,CAAC,SAAS;AAAA,IAChE;AACA,QAAI,OAAO,YAAY,QAAQ,OAAO,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,OAAO,GAAG;AAClG,YAAM,IAAI,MAAM,mBAAmB,CAAC,6BAA6B;AAAA,IACnE;AACA,UAAM,SAAS,mBAAmB,OAAO,QAAQ,QAAQ,mBAAmB,CAAC,kBAAkB;AAC/F,UAAM,MAAM,mBAAmB,OAAO,QAAQ,KAAK,mBAAmB,CAAC,eAAe;AACtF,UAAM,MAAM,mBAAmB,OAAO,QAAQ,KAAK,mBAAmB,CAAC,eAAe;AACtF,QAAI,SAAS,KAAK,MAAM,KAAK,MAAM,GAAG;AACpC,YAAM,IAAI,MAAM,mBAAmB,CAAC,gCAAgC;AAAA,IACtE;AACA,mBAAe,SAAS,MAAM;AAC9B,QAAI,OAAO,SAAS,QAAW;AAC7B,yBAAmB,OAAO,MAAM,mBAAmB,CAAC,QAAQ;AAAA,IAC9D;AAAA,EACF;AACA,MAAI,KAAK,IAAI,cAAc,CAAC,IAAI,MAAM;AACpC,UAAM,IAAI,MAAM,+CAA+C,YAAY,QAAQ,CAAC,CAAC,GAAG;AAAA,EAC1F;AACF;AAGO,SAAS,sBACd,QACoB;AACpB,MAAI,CAAC,OAAO,iBAAiB,OAAO,OAAO,kBAAkB,UAAU;AACrE,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,MAAI,CAAC,OAAO,iBAAiB,OAAO,OAAO,kBAAkB,UAAU;AACrE,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,QAAI,OAAO,eAAe,QAAW;AACnC,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AACA,QAAI,CAAC,MAAM,QAAQ,OAAO,MAAM,KAAK,OAAO,OAAO,WAAW,GAAG;AAC/D,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AACA,UAAM,OAAO,oBAAI,IAAY;AAC7B,eAAW,SAAS,OAAO,QAAQ;AACjC,UAAI,CAAC,MAAM,QAAQ,OAAO,MAAM,SAAS,UAAU;AACjD,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,UAAI,KAAK,IAAI,MAAM,IAAI,GAAG;AACxB,cAAM,IAAI,MAAM,yBAAyB,MAAM,IAAI,EAAE;AAAA,MACvD;AACA,WAAK,IAAI,MAAM,IAAI;AACnB,wBAAkB,MAAM,YAAY,UAAU,MAAM,IAAI,cAAc;AAAA,IACxE;AAAA,EACF;AACA,oBAAkB,OAAO,YAAY,YAAY;AACjD,oBAAkB,OAAO,aAAa,aAAa;AACnD,MAAI,OAAO,mBAAmB,WAAc,CAAC,OAAO,SAAS,OAAO,cAAc,KAAK,OAAO,iBAAiB,IAAI;AACjH,UAAM,IAAI,MAAM,6CAA6C,OAAO,cAAc,GAAG;AAAA,EACvF;AACA,MAAI,OAAO,YAAY,UAAa,OAAO,YAAY,iBAAiB,OAAO,YAAY,SAAS;AAClG,UAAM,IAAI,MAAM,iDAAiD,OAAO,OAAO,GAAG;AAAA,EACpF;AACA,MAAI,OAAO,WAAW,QAAW;AAC/B,eAAW,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC9D,UAAI,CAAC,MAAM,QAAQ,CAAC,uBAAuB,KAAK,MAAM,IAAI,GAAG;AAC3D,cAAM,IAAI,MAAM,UAAU,SAAS,iCAAiC,KAAK,UAAU,MAAM,IAAI,CAAC,GAAG;AAAA,MACnG;AACA,UAAI,MAAM,SAAS,WAAc,OAAO,MAAM,SAAS,YAAY,MAAM,KAAK,KAAK,MAAM,KAAK;AAC5F,cAAM,IAAI,MAAM,UAAU,SAAS,mCAAmC;AAAA,MACxE;AACA,UAAI,MAAM,mBAAmB,WAAc,CAAC,OAAO,SAAS,MAAM,cAAc,KAAK,MAAM,iBAAiB,IAAI;AAC9G,cAAM,IAAI,MAAM,UAAU,SAAS,+CAA+C,MAAM,cAAc,GAAG;AAAA,MAC3G;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,eAAe,QAAW;AACnC,QAAI,OAAO,eAAe,QAAQ,OAAO,OAAO,eAAe,YAAY,MAAM,QAAQ,OAAO,UAAU,GAAG;AAC3G,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,EACF;AACA,MAAI,OAAO,YAAY,QAAW;AAChC,mCAA+B,OAAO,SAAS,OAAO,OAAO;AAAA,EAC/D;AACA,MAAI,OAAO,mBAAmB,QAAW;AACvC,QAAI,CAAC,MAAM,QAAQ,OAAO,cAAc,KAAK,CAAC,OAAO,eAAe,MAAM,CAAC,MAAM,OAAO,MAAM,YAAY,EAAE,WAAW,IAAI,CAAC,GAAG;AAC7H,YAAM,IAAI,MAAM,+DAA+D;AAAA,IACjF;AAAA,EACF;AACA,MAAI,OAAO,YAAY,QAAW;AAChC,QAAI,OAAO,OAAO,YAAY,YAAY,OAAO,YAAY,QAAQ,MAAM,QAAQ,OAAO,OAAO,GAAG;AAClG,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AACA,0BAAsB,OAAO,SAA+C,CAAC,WAAW,SAAS,UAAU,GAAG,SAAS;AACvH,UAAM,oBAAoB,oBAAI,IAAY;AAC1C,QAAI,OAAO,QAAQ,YAAY,QAAW;AACxC,UAAI,CAAC,MAAM,QAAQ,OAAO,QAAQ,OAAO,GAAG;AAC1C,cAAM,IAAI,MAAM,kCAAkC;AAAA,MACpD;AACA,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,QAAQ,QAAQ,KAAK;AACtD,cAAM,SAAS,OAAO,QAAQ,QAAQ,CAAC;AACvC,YAAI,WAAW,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAC1E,gBAAM,IAAI,MAAM,mBAAmB,CAAC,qBAAqB;AAAA,QAC3D;AACA,8BAAsB,QAA8C,CAAC,OAAO,SAAS,QAAQ,aAAa,YAAY,OAAO,GAAG,mBAAmB,CAAC,GAAG;AACvJ,cAAM,MAAM,qBAAqB,OAAO,KAAK,mBAAmB,CAAC,OAAO;AACxE,YAAI,kBAAkB,IAAI,GAAG,GAAG;AAC9B,gBAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AAAA,QACxD;AACA,0BAAkB,IAAI,GAAG;AACzB,6BAAqB,OAAO,OAAO,mBAAmB,CAAC,SAAS;AAChE,YAAI,OAAO,SAAS,UAAa,OAAO,OAAO,SAAS,UAAU;AAChE,gBAAM,IAAI,MAAM,mBAAmB,CAAC,yBAAyB;AAAA,QAC/D;AACA,YAAI,OAAO,cAAc,UAAa,OAAO,cAAc,mBAAmB,OAAO,cAAc,gBAAgB;AACjH,gBAAM,IAAI,MAAM,mBAAmB,CAAC,uDAAuD;AAAA,QAC7F;AACA,YAAI,OAAO,aAAa,WAAc,CAAC,OAAO,UAAU,OAAO,QAAQ,KAAK,OAAO,WAAW,IAAI;AAChG,gBAAM,IAAI,MAAM,mBAAmB,CAAC,2CAA2C;AAAA,QACjF;AACA,YAAI,OAAO,UAAU,WAAc,CAAC,OAAO,UAAU,OAAO,KAAK,KAAK,OAAO,QAAQ,IAAI;AACvF,gBAAM,IAAI,MAAM,mBAAmB,CAAC,wCAAwC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,UAAU,QAAW;AACtC,UAAI,CAAC,MAAM,QAAQ,OAAO,QAAQ,KAAK,GAAG;AACxC,cAAM,IAAI,MAAM,gCAAgC;AAAA,MAClD;AACA,YAAM,eAAe,oBAAI,IAAY;AACrC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,MAAM,QAAQ,KAAK;AACpD,cAAM,OAAO,OAAO,QAAQ,MAAM,CAAC;AACnC,YAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AACpE,gBAAM,IAAI,MAAM,iBAAiB,CAAC,qBAAqB;AAAA,QACzD;AACA,8BAAsB,MAA4C,CAAC,OAAO,SAAS,OAAO,GAAG,iBAAiB,CAAC,GAAG;AAClH,cAAM,MAAM,qBAAqB,KAAK,KAAK,iBAAiB,CAAC,OAAO;AACpE,YAAI,aAAa,IAAI,GAAG,GAAG;AACzB,gBAAM,IAAI,MAAM,+BAA+B,GAAG,EAAE;AAAA,QACtD;AACA,qBAAa,IAAI,GAAG;AACpB,6BAAqB,KAAK,OAAO,iBAAiB,CAAC,SAAS;AAC5D,YAAI,KAAK,UAAU,WAAc,CAAC,OAAO,UAAU,KAAK,KAAK,KAAK,KAAK,QAAQ,IAAI;AACjF,gBAAM,IAAI,MAAM,iBAAiB,CAAC,wCAAwC;AAAA,QAC5E;AAAA,MACF;AAAA,IACF;AACA,QAAI,OAAO,QAAQ,aAAa,QAAW;AACzC,UAAI,OAAO,OAAO,QAAQ,aAAa,YAAY,OAAO,QAAQ,aAAa,QAAQ,MAAM,QAAQ,OAAO,QAAQ,QAAQ,GAAG;AAC7H,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AACA,4BAAsB,OAAO,QAAQ,UAAgD,CAAC,iBAAiB,eAAe,GAAG,kBAAkB;AAC3I,YAAM,EAAE,eAAe,cAAc,IAAI,OAAO,QAAQ;AACxD,UAAI,kBAAkB,QAAW;AAC/B,cAAM,SAAS,qBAAqB,eAAe,gCAAgC;AAGnF,cAAM,sBAAsB,IAAI,IAAI,iBAAiB;AACrD,4BAAoB,IAAI,gBAAgB;AACxC,4BAAoB,IAAI,MAAM;AAC9B,YAAI,OAAO,QAAQ,YAAY,UAAa,CAAC,oBAAoB,IAAI,MAAM,GAAG;AAC5E,gBAAM,IAAI,MAAM,mCAAmC,MAAM,wFAAwF;AAAA,QACnJ;AAAA,MACF;AACA,UAAI,kBAAkB,UAAa,CAAC,CAAC,WAAW,SAAS,SAAS,aAAa,EAAE,SAAS,aAAa,GAAG;AACxG,cAAM,IAAI,MAAM,sFAAsF;AAAA,MACxG;AAAA,IACF;AAAA,EACF;AACA,MAAI,OAAO,SAAS,UAAU,kBAAkB,oBAAoB,OAAO,YAAY,UAAa,OAAO,YAAY,QAAW;AAChI,UAAM,IAAI,MAAM,oGAAoG;AAAA,EACtH;AACA,SAAO;AACT;AAaO,SAAS,WACd,MACkB;AAClB,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AACA,SAAO;AACT;;;ACzkBO,IAAM,+BAAN,cAA2C,MAAM;AAAA,EAC7C;AAAA,EAET,YAAY,SAAgD;AAC1D;AAAA,MACE,yEACE,QAAQ,SAAS,IAAI,cAAc,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,MAAM,EAChF;AAAA,IACF;AACA,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AACF;;;ACFA,gCAAyB;AACzB,qBAAe;AACf,iBAAsC;AACtC,iBAA4B;AAC5B,oBAMO;;;ACsEP,SAAS,eAAe,GAAyB;AAC/C,SAAO,OAAO,MAAM,YAAY,OAAO,SAAS,CAAC;AACnD;AAEA,SAAS,WAAW,QAAkB,GAAmB;AACvD,MAAI,OAAO,WAAW,EAAG,QAAO;AAChC,QAAM,MAAM,KAAK,IAAI,GAAG,KAAK,KAAM,IAAI,MAAO,OAAO,MAAM,IAAI,CAAC;AAChE,SAAO,OAAO,KAAK,IAAI,KAAK,OAAO,SAAS,CAAC,CAAC;AAChD;AAEA,SAAS,aAAa,QAAkB,cAAsB,MAAoD;AAChH,MAAI,OAAO,WAAW,EAAG,QAAO,EAAE,QAAQ,GAAG,KAAK,GAAG,KAAK,EAAE;AAE5D,QAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAE/C,QAAM,YAAY,KAAK,MAAM,OAAO,SAAS,WAAW;AACxD,QAAM,UAAU,YAAY,KAAK,OAAO,SAAS,IAAI,YAAY,IAC7D,OAAO,MAAM,WAAW,OAAO,SAAS,SAAS,IACjD;AAEJ,QAAM,MAAM,KAAK,MAAM,QAAQ,SAAS,CAAC;AACzC,QAAM,SAAS,QAAQ,SAAS,MAAM,KACjC,QAAQ,MAAM,CAAC,IAAI,QAAQ,GAAG,KAAK,IACpC,QAAQ,GAAG;AAEf,SAAO,EAAE,QAAQ,KAAK,WAAW,SAAS,EAAE,GAAG,KAAK,WAAW,SAAS,EAAE,EAAE;AAC9E;AAEA,SAAS,aAAa,OAA4C;AAChE,SAAO,KAAK,MAAM,KAAK,UAAU,SAAS,CAAC,CAAC,CAAC;AAC/C;AAEA,SAAS,eAAe,QAAuB,SAAuC;AACpF,QAAM,UAAoB,CAAC;AAC3B,aAAW,UAAU,SAAS;AAC5B,UAAM,MAAM,OAAO,OAAO,UAAU,aAChC,OAAO,MAAM,MAAM,IACnB,OAAO,OAAO,OAAO,SAAS,OAAO,IAAI;AAE7C,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,iBAAW,QAAQ,KAAK;AACtB,YAAI,eAAe,IAAI,EAAG,SAAQ,KAAK,IAAI;AAAA,MAC7C;AAAA,IACF,WAAW,eAAe,GAAG,GAAG;AAC9B,cAAQ,KAAK,GAAG;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,UAAU,MAAc,QAA+B;AAC9D,MAAI,OAAO,gBAAgB;AACzB,UAAM,QAAQ,OAAO,SAAS;AAC9B,QAAI,QAAQ,MAAO,QAAO;AAC1B,QAAI,QAAQ,OAAO,QAAS,QAAO;AACnC,YAAS,OAAO,UAAU,OAAO,UAAU,SAAU;AAAA,EACvD;AACA,SAAO,KAAK,IAAI,GAAG,OAAO,IAAI,OAAO,OAAO,QAAQ;AACtD;AAEO,IAAM,gBAA+B,CAAC,MAAM,UAAU;AAAA,EAC3D;AAAA,EACA,GAAG;AAAA,EACH,gBAAgB;AAClB;AAEO,IAAM,iBAAiC,CAAC,MAAM,UAAU;AAAA,EAC7D;AAAA,EACA,GAAG;AAAA,EACH,gBAAgB;AAClB;AAEA,IAAM,uBAAuB;AAMtB,IAAM,mBAAN,cAA+B,MAAM;AAAA,EAC1C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AASO,SAAS,oBAAoB,MAAyB;AAC3D,QAAM,cAAc,KAAK,QAAQ;AAAA,IAC/B,CAAC,KAAK,MAAM,MAAM,EAAE,QAAQ,SAAS,EAAE,QAAQ,MAAM,EAAE,QAAQ;AAAA,IAC/D;AAAA,EACF;AACA,MAAI,KAAK,IAAI,cAAc,CAAC,IAAI,sBAAsB;AACpD,UAAM,YAAY,KAAK,QACpB,IAAI,CAAC,MAAM,GAAG,EAAE,IAAI,KAAK,EAAE,QAAQ,SAAS,EAAE,QAAQ,MAAM,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,EAAE,EACvF,KAAK,IAAI;AACZ,UAAM,IAAI;AAAA,MACR,+BAA+B,YAAY,QAAQ,CAAC,CAAC,uBAChD,oBAAoB,4LAEqB,aAAa,uBAAuB;AAAA,IACpF;AAAA,EACF;AACF;AAEA,SAAS,kBACP,SACA,KACmD;AACnD,QAAM,SAAS,oBAAI,IAA6D;AAChF,aAAW,UAAU,SAAS;AAC5B,UAAM,MAAM,OAAO,OAAO,GAAG;AAC7B,UAAM,QAAQ,QAAQ,SAAY,SAAY;AAC9C,UAAM,SAAS,UAAU,SAAY,kBAAkB,KAAK,UAAU,KAAK;AAC3E,QAAI,QAAQ,OAAO,IAAI,MAAM;AAC7B,QAAI,CAAC,OAAO;AACV,cAAQ,EAAE,OAAO,SAAS,CAAC,EAAE;AAC7B,aAAO,IAAI,QAAQ,KAAK;AAAA,IAC1B;AACA,UAAM,QAAQ,KAAK,MAAM;AAAA,EAC3B;AACA,SAAO,MAAM,KAAK,OAAO,OAAO,CAAC;AACnC;AAEA,SAAS,WACP,SACA,MACA,gBACA,UACA,YACA,UACA,cACsB;AACtB,QAAM,gBAAgB,KAAK,YAAY,CAAC,MAAwB,EAAE,WAAW;AAC7E,QAAM,UAAU,QAAQ,OAAO,aAAa;AAC5C,QAAM,cAAc,QAAQ,WAAW,IAAI,IAAI,QAAQ,SAAS,QAAQ;AACxE,QAAM,UAAU,QAAQ,WAAW;AAEnC,MAAI,kBAAkB;AACtB,QAAM,UAA2C,CAAC;AAElD,aAAW,UAAU,KAAK,SAAS;AACjC,UAAM,UAAU,eAAe,QAAQ,OAAO;AAG9C,QAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,IACF;AACA,UAAM,EAAE,QAAQ,KAAK,IAAI,IAAI,aAAa,SAAS,OAAO,QAAQ,IAAI;AACtE,UAAM,cACJ,OAAO,QAAQ,SAAS,UAAU,QAAQ,MAAM,IAChD,OAAO,QAAQ,MAAM,UAAU,KAAK,MAAM,IAC1C,OAAO,QAAQ,MAAM,UAAU,KAAK,MAAM;AAC5C,uBAAmB;AAEnB,UAAM,UAAU,OAAO,OAAO,UAAU,WAAW,OAAO,QAAQ,OAAO;AACzE,UAAM,OAAO,OAAO,QAAQ,aAAa,IAAI,OAAO,KAAK;AACzD,YAAQ,KAAK,EAAE,MAAM,OAAO,MAAM,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,EAC5D;AAEA,QAAM,iBAAiB,gBAAgB,IAAI,IAAI,KAAK,MAAM,kBAAkB,cAAc,GAAG,IAAI;AAEjG,QAAM,aAAa,aAAa;AAAA,IAC9B,GAAG;AAAA,IACH,GAAI,aAAa,UAAa,eAAe,SAAY,EAAE,CAAC,QAAQ,GAAG,WAAW,IAAI,CAAC;AAAA,EACzF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,MACd,SACA,MACA,gBACwB;AACxB,sBAAoB,IAAI;AACxB,QAAM,iBAAiB,aAAa,KAAK,cAAc,CAAC,CAAC;AACzD,QAAM,eAAe,IAAI,IAAI,gBAAgB,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACxE,QAAM,UAAkC,CAAC;AAEzC,aAAW,EAAE,aAAa,QAAQ,KAAK,QAAQ,cAAc;AAG3D,UAAM,SAAS,KAAK,WAAW,QAAQ,SAAS,IAC5C,CAAC,EAAE,OAAO,QAAW,QAAQ,GAAG,GAAG,kBAAkB,SAAS,KAAK,OAAO,CAAC,IAC3E,CAAC,EAAE,OAAO,QAAW,QAAQ,CAAC;AAElC,eAAW,SAAS,QAAQ;AAC1B,cAAQ,KAAK,WAAW,MAAM,SAAS,MAAM,gBAAgB,KAAK,SAAS,MAAM,OAAO,aAAa,YAAY,CAAC;AAAA,IACpH;AAAA,EACF;AAEA,SAAO;AACT;AAGO,SAAS,oBACd,QACA,YACA,SACa;AACb,QAAM,UAAU,OAAO;AACvB,QAAM,eAAe,IAAI,IAAI,SAAS,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AAC1E,SAAO;AAAA,IACL,GAAI,aAAa,EAAE,YAAY,aAAa,UAAU,EAAE,IAAI,CAAC;AAAA,IAC7D,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACpD,GAAI,UACA;AAAA,MACA,SAAS,CAAC,WACR,OAAO,WAAW,aAClB,OAAO,QAAQ,QAAQ,WAAW,EAAE,MAAM,CAAC,CAAC,KAAK,KAAK,MAAM,OAAO,OAAO,GAAG,MAAM,KAAK;AAAA,IAC5F,IACE,CAAC;AAAA,IACL,SAAS,OAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,MACvC,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,MACd,OAAO,SAAS,YAAY,SAAY,OAAO,OAAQ,aAAa,IAAI,OAAO,GAAG,KAAK,OAAO,SAAU;AAAA,MACxG,SAAS,OAAO;AAAA,MAChB,OAAO,OAAO;AAAA,MACd,gBAAgB,OAAO;AAAA,MACvB,SAAS,OAAO;AAAA,MAChB,MAAM,OAAO;AAAA,IACf,EAAE;AAAA,EACJ;AACF;;;AClUA,IAAM,kBAAuC,CAAC,SAAS,QAAQ,QAAQ,OAAO;AAE9E,SAAS,aAAa,OAA8C;AAClE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,QAAM,IAAI;AACV,QAAM,OAAO,OAAO,KAAK,CAAC;AAC1B,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,MAAI,CAAC,KAAK,MAAM,CAAC,MAAM,MAAM,WAAW,MAAM,MAAM,EAAG,QAAO;AAC9D,MAAI,EAAE,UAAU,WAAc,OAAO,EAAE,UAAU,YAAY,CAAC,gBAAgB,SAAS,EAAE,KAA0B,IAAI;AACrH,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,IAAM,YAAN,MAAgB;AAAA,EACJ,QAAkB,CAAC;AAAA,EAEpC,KAAK,WAAmB,UAAkB,SAAqC;AAC7E,UAAM,SAAS,SAAS,SAAS,KAAK,QAAQ;AAC9C,SAAK,MAAM,KAAK,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,MAAM,EAAE;AACvD,QAAI,QAAQ,QAAQ,KAAK,GAAG;AAC1B,WAAK,MAAM,KAAK,OAAO,QAAQ,MAAM,CAAC;AAAA,IACxC;AACA,QAAI,QAAQ,QAAQ,KAAK,GAAG;AAC1B,WAAK,MAAM,KAAK,OAAO,QAAQ,QAAQ,UAAU,CAAC;AAAA,IACpD;AACA,QAAI,QAAQ,OAAO;AACjB,WAAK,MAAM,KAAK,OAAO,QAAQ,OAAO,SAAS,CAAC;AAAA,IAClD;AAAA,EACF;AAAA;AAAA,EAGA,KAAK,SAAiB,eAAqE;AACzF,UAAM,OAAqE,aAAa,aAAa,IACjG,EAAE,OAAO,cAAc,SAAS,QAAQ,MAAM,cAAc,KAAK,IACjE,EAAE,OAAO,QAAQ,MAAM,cAAc;AACzC,UAAM,SAAS,KAAK,QAAQ,OAAO,KAAK,KAAK,IAAI,EAAE,SAAS,IAAI,IAAI,KAAK,UAAU,KAAK,IAAI,CAAC,KAAK;AAIlG,UAAM,YAAY,QAAQ,MAAM,yBAAyB;AACzD,QAAI,WAAW;AACb,WAAK,MAAM,KAAK,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,UAAU,CAAC,CAAC,KAAK,KAAK,KAAK,KAAK,UAAU,CAAC,CAAC,GAAG,MAAM,EAAE;AAAA,IACxG,OAAO;AACL,WAAK,MAAM,KAAK,IAAG,oBAAI,KAAK,GAAE,YAAY,CAAC,KAAK,KAAK,KAAK,KAAK,OAAO,GAAG,MAAM,EAAE;AAAA,IACnF;AAAA,EACF;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,MAAM,WAAW;AAAA,EAC/B;AAAA,EAEA,SAAiB;AACf,WAAO,KAAK,MAAM,KAAK,IAAI,IAAI;AAAA,EACjC;AACF;AAEA,SAAS,OAAO,MAAc,SAAS,IAAY;AACjD,SAAO,KACJ,QAAQ,EACR,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,MAAM,GAAG,IAAI,EAAE,EAClC,KAAK,IAAI;AACd;;;AFIA,SAAS,gBAAyB;AAChC,QAAM,IAAI,QAAQ,IAAI;AACtB,SAAO,MAAM,OAAO,GAAG,YAAY,MAAM;AAC3C;AAEA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAACA,aAAY,WAAWA,UAAS,EAAE,CAAC;AACzD;AAMA,SAAS,mBAAsB,KAA8B,OAA6B;AACxF,MAAI,SAAS,IAAI,UAAU,IAAI,WAAW,GAAG;AAC3C,WAAO,QAAQ,IAAI,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;AAAA,EAC1C;AAEA,QAAM,UAAU,IAAI,MAAS,IAAI,MAAM;AACvC,MAAI,UAAU;AACd,MAAI,YAAY;AAChB,MAAI,YAAY;AAEhB,SAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,UAAM,UAAU,MAAM;AACpB,UAAI,cAAc,IAAI,QAAQ;AAC5B,QAAAA,SAAQ,OAAO;AACf;AAAA,MACF;AACA,aAAO,UAAU,SAAS,YAAY,IAAI,QAAQ;AAChD,cAAM,QAAQ;AACd;AACA,YAAI,KAAK,EAAE,EAAE;AAAA,UACX,CAAC,UAAU;AACT,oBAAQ,KAAK,IAAI;AACjB;AACA;AACA,oBAAQ;AAAA,UACV;AAAA,UACA,CAAC,UAAU,OAAO,KAAK;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AACA,YAAQ;AAAA,EACV,CAAC;AACH;AAEA,SAAS,aAAa,OAAwB;AAC5C,MAAI,iBAAiB,SAAS,UAAU,SAAS,OAAQ,MAA4B,SAAS,YAAa,MAA2B,MAAM;AAC1I,WAAQ,MAA2B;AAAA,EACrC;AACA,MAAI,iBAAiB,SAAS,MAAM,KAAM,QAAO,MAAM;AACvD,SAAO;AACT;AAEA,SAAS,YAAY,OAAoC;AACvD,SAAO,iBAAiB,UAAU,iBAAiB,aAAa,MAAM,SAAS;AACjF;AAEA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,UAAU,UAAU,SAAS,YAAY,QAAQ,UAAU,KAAK,CAAC;AAEpG,SAAS,cAAc,OAA+C;AACpE,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,EAAG,QAAO;AACxE,QAAM,IAAI;AACV,QAAM,OAAO,OAAO,KAAK,CAAC;AAC1B,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,MAAI,CAAC,KAAK,MAAM,CAAC,MAAM,kBAAkB,IAAI,CAAC,CAAC,EAAG,QAAO;AACzD,SAAO,OAAO,EAAE,WAAW,YAAY,OAAO,EAAE,WAAW,YAAY,OAAO,EAAE,UAAU;AAC5F;AAEA,SAAS,YAAe,SAAqB,IAAY,MAA0B;AACjF,SAAO,IAAI,QAAQ,CAACA,UAAS,WAAW;AACtC,UAAM,QAAQ;AAAA,MACZ,MAAM,OAAO,IAAI,UAAU,SAAS,IAAI,qBAAqB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC,CAAC;AAAA,MAC9F;AAAA,IACF;AACA,YAAQ;AAAA,MACN,CAAC,UAAU;AACT,qBAAa,KAAK;AAClB,QAAAA,SAAQ,KAAK;AAAA,MACf;AAAA,MACA,CAAC,UAAU;AACT,qBAAa,KAAK;AAClB,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAe,mBACb,MACA,IACA,SACkB;AAClB,QAAM,uBAAuB,SAAS;AACtC,MAAI,yBAAyB,WAAc,CAAC,OAAO,UAAU,oBAAoB,KAAK,uBAAuB,IAAI;AAC/G,UAAM,IAAI,MAAM,SAAS,IAAI,8CAA8C,oBAAoB,GAAG;AAAA,EACpG;AACA,QAAM,YAAY,SAAS;AAC3B,MAAI,cAAc,WAAc,CAAC,OAAO,SAAS,SAAS,KAAK,YAAY,IAAI;AAC7E,UAAM,IAAI,MAAM,SAAS,IAAI,0CAA0C,SAAS,GAAG;AAAA,EACrF;AAEA,QAAM,QAAQ,wBAAwB;AACtC,QAAM,cAAc,MAAM,KAAK,EAAE,QAAQ,MAAM,GAAG,MAAM;AACtD,UAAM,UAAU,QAAQ,QAAQ,EAAE,KAAK,MAAM,GAAG,CAAC;AACjD,QAAI,cAAc,OAAW,QAAO;AACpC,WAAO,YAAY,SAAS,WAAW,IAAI;AAAA,EAC7C,CAAC;AAED,MAAI,UAAU,GAAG;AACf,WAAO,YAAY,CAAC;AAAA,EACtB;AAEA,QAAM,WAAW,MAAM,QAAQ,WAAW,WAAW;AACrD,QAAM,UAAe,CAAC;AACtB,MAAI;AACJ,aAAW,WAAW,UAAU;AAC9B,QAAI,QAAQ,WAAW,aAAa;AAClC,cAAQ,KAAK,QAAQ,KAAK;AAAA,IAC5B,WAAW,eAAe,QAAW;AACnC,mBAAa,QAAQ;AAAA,IACvB;AAAA,EACF;AACA,MAAI,eAAe,OAAW,OAAM;AACpC,SAAO;AACT;AAEA,eAAe,kBACb,YACA,MACA,IACA,SACgC;AAChC,QAAM,EAAE,aAAa,mBAAmB,WAAW,GAAG,cAAc,IAAI,WAAW,CAAC;AACpF,QAAM,oBAAuC;AAAA,IAC3C,GAAG;AAAA,IACH;AAAA,IACA,iBAAiB;AAAA,EACnB;AACA,QAAM,SAAS,MAAM,WAAW,MAAM,MAAM,mBAAmB,MAAM,IAAI,OAAO,GAAG,iBAAiB;AACpG,SAAO;AACT;AAWO,SAAS,aAAa,MAAgB,oBAAiD;AAC5F,QAAM,OAAgB,CAAC;AACvB,QAAM,UAAoB,CAAC;AAC3B,QAAM,UAAU,IAAI,IAAI,sBAAsB,CAAC,CAAC;AAEhD,QAAM,YAAY,CAAC,KAAa,MAAoD;AAClF,UAAM,KAAK,IAAI,QAAQ,GAAG;AAC1B,QAAI,OAAO,GAAI,QAAO,EAAE,OAAO,IAAI,MAAM,KAAK,CAAC,GAAG,WAAW,EAAE;AAC/D,WAAO,EAAE,OAAO,KAAK,IAAI,CAAC,KAAK,IAAI,WAAW,IAAI,EAAE;AAAA,EACtD;AAEA,QAAM,UAAU,CAAC,KAAa,SAAyB;AACrD,QAAI,IAAI,KAAK,MAAM,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,kBAAkB;AAChE,UAAM,IAAI,OAAO,GAAG;AACpB,QAAI,CAAC,OAAO,UAAU,CAAC,KAAK,IAAI,EAAG,OAAM,IAAI,MAAM,GAAG,IAAI,kCAAkC,GAAG,IAAI;AACnG,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,KAAa,SAAyB;AACxD,QAAI,IAAI,KAAK,MAAM,GAAI,OAAM,IAAI,MAAM,GAAG,IAAI,kBAAkB;AAChE,UAAM,IAAI,OAAO,GAAG;AACpB,QAAI,CAAC,OAAO,SAAS,CAAC,KAAK,IAAI,EAAG,OAAM,IAAI,MAAM,GAAG,IAAI,gCAAgC,GAAG,IAAI;AAChG,WAAO;AAAA,EACT;AAEA,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,UAAM,OAAO,IAAI,SAAS,GAAG,IAAI,IAAI,MAAM,GAAG,IAAI,QAAQ,GAAG,CAAC,IAAI;AAClE,YAAQ,MAAM;AAAA;AAAA,MAEZ,KAAK;AAAA,MACL,KAAK,eAAe;AAClB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,YAAI,CAAC,uBAAuB,KAAK,KAAK,GAAG;AACvC,gBAAM,IAAI,MAAM,GAAG,IAAI,6CAA6C,KAAK,IAAI;AAAA,QAC/E;AACA,aAAK,YAAY;AACjB,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,UAAU;AACb,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,YAAI,MAAM,KAAK,MAAM,GAAI,OAAM,IAAI,MAAM,wBAAwB;AACjE,aAAK,OAAO;AACZ,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,WAAW;AACd,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,YAAI,MAAM,KAAK,MAAM,GAAI,OAAM,IAAI,MAAM,yBAAyB;AAClE,aAAK,QAAQ;AACb,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,aAAa;AAChB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,YAAI,MAAM,KAAK,MAAM,GAAI,OAAM,IAAI,MAAM,2BAA2B;AACpE,aAAK,SAAS;AACd,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,aAAK,aAAa,QAAQ,OAAO,cAAc;AAC/C,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,aAAK,cAAc,QAAQ,OAAO,eAAe;AACjD,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,sBAAsB;AACzB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,aAAK,iBAAiB,WAAW,OAAO,oBAAoB;AAC5D,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,YAAI,UAAU,iBAAiB,UAAU,SAAS;AAChD,gBAAM,IAAI,MAAM,qDAAqD,KAAK,IAAI;AAAA,QAChF;AACA,aAAK,UAAU;AACf,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,EAAE,OAAO,UAAU,IAAI,UAAU,KAAK,CAAC;AAC7C,cAAM,QAAQ,MAAM,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,OAAO;AAClE,aAAK,YAAY,CAAC,GAAI,KAAK,aAAa,CAAC,GAAI,GAAG,KAAK;AACrD,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AACH,aAAK,WAAW;AAChB;AAAA,MACF,SAAS;AACP,YAAI,QAAQ,IAAI,IAAI,GAAG;AAGrB,cAAI,CAAC,IAAI,SAAS,GAAG,GAAG;AACtB,kBAAM,OAAO,KAAK,IAAI,CAAC;AACvB,gBAAI,QAAQ,CAAC,KAAK,WAAW,GAAG,GAAG;AACjC;AAAA,YACF;AAAA,UACF;AAAA,QACF,OAAO;AACL,kBAAQ,KAAK,IAAI;AAGjB,cAAI,CAAC,IAAI,SAAS,GAAG,GAAG;AACtB,kBAAM,OAAO,KAAK,IAAI,CAAC;AACvB,gBAAI,QAAQ,CAAC,KAAK,WAAW,GAAG,GAAG;AACjC;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,SAAS,GAAG;AACtB,UAAM,IAAI,MAAM,oBAAoB,QAAQ,KAAK,IAAI,CAAC,EAAE;AAAA,EAC1D;AAEA,MAAI,CAAC,KAAK,YAAY,cAAc,GAAG;AACrC,SAAK,WAAW;AAAA,EAClB;AACA,SAAO;AACT;AAGO,SAAS,YACd,QACA,MACmB;AAMnB,QAAM,SAAS,OAAO;AACtB,QAAM,eAAe,WAAW,UAAa,OAAO,KAAK,CAAC,MAAM,EAAE,eAAe,OAAO,CAAC,EAAE,UAAU;AACrG,MAAI,gBAAgB,KAAK,eAAe,QAAW;AACjD,YAAQ,KAAK,+EAA+E;AAAA,EAC9F;AACA,QAAM,kBAAkB,WAAW,UAAa,CAAC,eAAe,KAAK,aAAa;AAClF,QAAM,aACJ,WAAW,SACN,oBAAoB,SACjB,kBAAkB,OAAO,SACzB,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,YAAY,CAAC,IACnD;AACN,QAAM,WAA8B;AAAA,IAClC,YAAY,cAAc,KAAK,cAAc,OAAO,cAAc;AAAA,IAClE;AAAA,IACA,aAAa,KAAK,eAAe,OAAO,eAAe;AAAA,IACvD,gBAAgB,KAAK,kBAAkB,OAAO,kBAAkB;AAAA,IAChE,SAAS,KAAK,WAAW,OAAO,WAAW;AAAA,IAC3C,WAAW,KAAK,aAAa,OAAO;AAAA,EACtC;AACA,MAAI,CAAC,OAAO,UAAU,SAAS,UAAU,KAAK,SAAS,aAAa,GAAG;AACrE,UAAM,IAAI,MAAM,2CAA2C,SAAS,UAAU,GAAG;AAAA,EACnF;AACA,MAAI,CAAC,OAAO,UAAU,SAAS,WAAW,KAAK,SAAS,cAAc,GAAG;AACvE,UAAM,IAAI,MAAM,4CAA4C,SAAS,WAAW,GAAG;AAAA,EACrF;AACA,SAAO;AACT;AAcA,SAAS,cACP,QACA,UACA,MACW;AACX,MAAI,OAAO,QAAQ,QAAQ;AACzB,WAAO,OAAO,OAAO;AAAA,MAAQ,CAAC,UAC5B,MAAM,KAAK,EAAE,QAAQ,SAAS,mBAAmB,MAAM,WAAW,GAAG,OAAO;AAAA,QAC1E,OAAO,MAAM;AAAA,QACb;AAAA,MACF,EAAE;AAAA,IACJ;AAAA,EACF;AACA,SAAO,MAAM,KAAK,EAAE,QAAQ,SAAS,WAAW,GAAG,OAAO,EAAE,OAAO,QAAW,KAAK,EAAE;AACvF;AAIA,SAAS,gBAAgB,QAA0B,MAAyD;AAC1G,QAAM,IAAI,OAAO,YAAY;AAC7B,MAAI,OAAO,WAAW,WAAW;AAC/B,UAAM,OAAO,OAAO,QAAQ,OAAO,KAAK,OAAO,IAAI,EAAE,SAAS,IAAI,IAAI,KAAK,UAAU,OAAO,IAAI,CAAC,KAAK;AACtG,YAAQ,IAAI,MAAM,KAAK,WAAW,UAAU,CAAC,IAAI,KAAK,UAAU,YAAY,IAAI,EAAE;AAAA,EACpF,OAAO;AACL,YAAQ,IAAI,MAAM,KAAK,WAAW,UAAU,CAAC,IAAI,KAAK,UAAU,mBAAc,OAAO,aAAa,eAAe,EAAE;AAAA,EACrH;AACF;AAOA,SAAS,aACP,QACA,WAC4B;AAC5B,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,QAAQ,OAAO,SAAS,SAAS;AACvC,MAAI,CAAC,OAAO;AACV,UAAM,QAAQ,OAAO,KAAK,OAAO,UAAU,CAAC,CAAC;AAC7C,UAAM,IAAI;AAAA,MACR,MAAM,SAAS,IACX,oBAAoB,SAAS,oBAAoB,MAAM,KAAK,IAAI,CAAC,MACjE,oBAAoB,SAAS;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;AAOA,SAAS,WACP,QACA,OACoB;AACpB,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,eAAe,MAAM;AAAA,IACrB,eAAe,MAAM,QAAQ,MAAM;AAAA,IACnC,GAAI,MAAM,mBAAmB,SAAY,EAAE,gBAAgB,MAAM,eAAe,IAAI,CAAC;AAAA,EACvF;AACF;AAGA,SAAS,uBACP,YACA,MACoB;AACpB,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAI,KAAK,YAAY,EAAE,eAAe,KAAK,UAAU,IAAI,CAAC;AAAA,IAC1D,GAAI,KAAK,OAAO,EAAE,eAAe,KAAK,KAAK,IAAI,CAAC;AAAA,EAClD;AACF;AAEA,SAAS,gBAAgB,SAAiB,kBAA0B,eAAuB,OAAuB;AAChH,SAAO,GAAG,QAAQ,QAAQ,iBAAiB,EAAE,CAAC,IAAI,gBAAgB,eAAe,aAAa,SAAS,KAAK;AAC9G;AAGA,SAAS,oBAA+C,QAA4B,UAAkC;AACpH,QAAM,EAAE,WAAW,QAAQ,QAAI,2CAAwB,kCAAmB,OAAO,cAAc,SAAS,SAAS,CAAC;AAClH,aAAW,KAAK,SAAS;AACvB,YAAQ,IAAI,YAAY,EAAE,IAAI,aAAa,EAAE,QAAQ,KAAK,IAAI,CAAC,EAAE;AAAA,EACnE;AACA,MAAI,UAAU,WAAW,EAAG,OAAM,IAAI,6BAA6B,OAAO;AAC1E,SAAO;AACT;AAGA,SAAS,gBACP,QACA,UACA,cACY;AACZ,QAAM,SAAS,OAAO,QAAQ,IAAI,CAAC,WAAW;AAAA,IAC5C,MAAM,MAAM;AAAA,IACZ,YAAY,SAAS,mBAAmB,MAAM;AAAA,EAChD,EAAE;AACF,QAAM,YAAY;AAAA,IAChB,eAAe,OAAO;AAAA,IACtB,eAAe,OAAO;AAAA,IACtB,GAAI,SAAS,oBAAoB,SAAY,EAAE,iBAAiB,SAAS,gBAAgB,IAAI,CAAC;AAAA,IAC9F,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,IAC3B,GAAI,CAAC,OAAO,SAAS,EAAE,YAAY,SAAS,WAAW,IAAI,CAAC;AAAA,IAC5D,aAAa,SAAS;AAAA,IACtB,gBAAgB,SAAS;AAAA,IACzB,SAAS,SAAS;AAAA,IAClB,GAAI,OAAO,aAAa,EAAE,YAAY,OAAO,WAAW,IAAI,CAAC;AAAA,IAC7D,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;AAAA,IACpD;AAAA,EACF;AACA,SAAO,KAAK,MAAM,KAAK,UAAU,SAAS,CAAC;AAC7C;AAWA,eAAsB,aACpB,YACA,MACA,OAAiB,CAAC,GACY;AAC9B,QAAM,OAAO,aAAa,MAAM,WAAW,cAAc;AACzD,QAAM,WAAW,KAAK,YAAY,cAAc;AAChD,QAAM,SAAS,WAAW,YAAY,aAAa,YAAY,KAAK,KAAK,CAAC;AAC1E,QAAM,SAAS,uBAAuB,QAAQ,IAAI;AAClD,QAAM,WAAW,YAAY,QAAQ,IAAI;AAEzC,QAAM,OAAO,UAAM,wBAAY;AAC/B,QAAM,aAAS,kCAAsB;AAAA,IACnC,SAAS,KAAK;AAAA,IACd,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,IACZ,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,EACd,CAAC;AAED,QAAM,YAAY,oBAAoB,QAAQ,QAAQ;AAEtD,QAAM,WAAW,cAAc,QAAQ,UAAU,IAAI;AACrD,QAAM,aAAa,SAAS;AAE5B,QAAM,mBAAmB,OAAO,SAAS,WAAW;AACpD,UAAQ,IAAI,GAAG,OAAO,aAAa,mBAAmB;AACtD,UAAQ,IAAI,UAAS,oBAAI,KAAK,GAAE,YAAY,CAAC,EAAE;AAC/C,MAAI,UAAU;AACZ,YAAQ,IAAI,6CAA6C;AAAA,EAC3D;AACA,UAAQ;AAAA,IACN,qBAAqB,UAAU,iBAAiB,gBAAgB,oBAC5C,SAAS,cAAc,aAAa,SAAS,OAAO;AAAA;AAAA,EAC1E;AAMA,QAAM,iBACJ,KAAK,UAAU,UACf,KAAK,SAAS,UACd,CAAC,KAAK,aACN,KAAK,cAAc,WAAW;AAEhC,MAAI;AACJ,MAAI;AACJ,MAAI,UAAU;AACZ,YAAQ;AACR,mBAAe;AAAA,EACjB,OAAO;AACL,QAAI,gBAAgB;AAClB,YAAM,kBAA8B;AAAA,QAClC,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAiC,IAAI,CAAC;AAAA,QAC7E,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAiC,IAAI,CAAC;AAAA,MAC/E;AACA,YAAM,OAAQ,gBAAgB,OAAO,eAAe;AAAA,QAClD,MAAM,OAAO;AAAA,QACb,GAAI,OAAO,KAAK,eAAe,EAAE,SAAS,IAAI,EAAE,QAAQ,gBAAgB,IAAI,CAAC;AAAA,MAC/E,CAAC;AAAA,IACH;AAEA,UAAM,YAAY,SACd,gBAAgB,QAAQ,UAAU,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAC9D,CAAC;AAEL,QAAI,KAAK,QAAQ;AAKf,YAAM,EAAE,KAAAC,MAAK,iBAAiB,IAAI,MAAM,OAAQ,UAAU,OAAO,eAAe;AAAA,QAC9E,QAAQ,KAAK;AAAA,QACb,QAAQ;AAAA,MACV,CAAC;AACD,cAAQA,KAAI;AACZ,qBAAe,gBAAgB,KAAK,YAAY,kBAAkB,OAAO,eAAeA,KAAI,EAAE;AAC9F,iBAAW,eAAe,WAAW;AACnC,cAAM,OAAQ,kBAAkB,OAAO,eAAe,OAAO,YAAY,MAAM,EAAE,WAAW,CAAC;AAAA,MAC/F;AACA,cAAQ,IAAI,oBAAoB,KAAK,MAAM,OAAOA,KAAI,IAAI,KAAK,KAAK,GAAG;AACvE,cAAQ,IAAI,YAAY,YAAY;AAAA,CAAI;AAAA,IAC1C,OAAO;AACL,YAAM,EAAE,KAAAA,MAAK,iBAAiB,IAAI,MAAM,OAAQ,UAAU,OAAO,eAAe;AAAA,QAC9E;AAAA,QACA,aAAa;AAAA,QACb,cAAc,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,QACzC,QAAQ;AAAA,MACV,CAAC;AACD,cAAQA,KAAI;AACZ,qBAAe,gBAAgB,KAAK,YAAY,kBAAkB,OAAO,eAAeA,KAAI,EAAE;AAC9F,cAAQ,IAAI,gBAAgBA,KAAI,IAAI,KAAK,KAAK,GAAG;AACjD,cAAQ,IAAI,YAAY,YAAY;AAAA,CAAI;AAAA,IAC1C;AAAA,EACF;AAEA,QAAM,WAAW;AAEjB,MAAI;AACJ,MAAI,SAAS,YAAY,SAAS;AAChC,yBAAqB,MAAM,kBAAkB,QAAQ,UAAU,WAAW,UAAU,QAAQ,OAAO,KAAK,YAAY,KAAK,QAAQ,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO,UAAU,QAAQ;AAAA,EAC3L,OAAO;AACL,yBAAqB,MAAM,wBAAwB,QAAQ,UAAU,WAAW,UAAU,QAAQ,OAAO,UAAU,QAAQ;AAAA,EAC7H;AAEA,UAAQ,IAAI,aAAa,WAAW,6BAA6B,YAAY,YAAY,EAAE,EAAE;AAC7F,QAAM,UAA+B;AAAA,IACnC;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,QAAQ;AAAA,EACV;AACA,MAAI,CAAC,aAAa,OAAO,WAAW,OAAO,UAAU;AACnD,QAAI;AACF,YAAM,OAAO,OAAO,UAChB,MAAM,OAAO,QAAQ,eAAe,cAAc,IAClD,oBAAoB,OAAO,SAAU,OAAO,YAAY,OAAO,OAAO;AAC1E,YAAM,SAAS,MAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAC3D,YAAMA,OAAM;AAAA,QACV,QAAQ,QAAQ,IAAI,cAAc,UAAU;AAAA,QAC5C,QAAQ,QAAQ,IAAI,mBAAmB,QAAQ,IAAI,cAAc,UAAU;AAAA,QAC3E,aAAa,QAAQ,IAAI,qBAAqB;AAAA,QAC9C,aAAa,QAAQ;AAAA,QACrB,UAAU,eAAAC,QAAG,SAAS;AAAA,QACtB,MAAM,eAAAA,QAAG,KAAK;AAAA,MAChB;AACA,YAAM,OAAO,iBAAiB,OAAO,eAAe,OAAO;AAAA,QACzD,KAAAD;AAAA,QACA,SAAS;AAAA,QACT,GAAI,OAAO,UAAU,EAAE,SAAS,OAAO,QAAiC,IAAI,CAAC;AAAA,MAC/E,CAAC;AAAA,IACH,SAAS,KAAK;AAIZ,UAAI,eAAe,iBAAkB,OAAM;AAC3C,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,cAAQ,KAAK,mDAAmD,OAAO,EAAE;AAAA,IAC3E;AAAA,EACF;AACA,MAAI,OAAO,WAAY,OAAM,OAAO,WAAW,OAAO;AACtD,SAAO;AACT;AAEA,SAAS,YAAgC;AACvC,MAAI,QAAQ,IAAI,WAAY,QAAO,QAAQ,IAAI;AAC/C,MAAI;AACF,eAAO,oCAAS,sBAAsB,EAAE,UAAU,QAAQ,OAAO,OAAO,CAAC,EAAE,KAAK;AAAA,EAClF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,YAAgC;AACvC,MAAI,QAAQ,IAAI,gBAAiB,QAAO,QAAQ,IAAI;AACpD,MAAI,QAAQ,IAAI,WAAY,QAAO,QAAQ,IAAI;AAC/C,MAAI;AACF,eAAO,oCAAS,mCAAmC,EAAE,UAAU,QAAQ,OAAO,OAAO,CAAC,EAAE,KAAK;AAAA,EAC/F,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,eAAe,wBACb,QACA,UACA,WACA,UACA,QACA,OACA,UACA,UAC+B;AAC/B,QAAM,qBAA2C,CAAC;AAClD,aAAW,eAAe,WAAW;AACnC,YAAQ,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC,EAAE;AAC/B,YAAQ,IAAI,kBAAkB,YAAY,IAAI,EAAE;AAChD,YAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAG1B,QAAI,YAAY,CAAC,QAAQ;AACvB,YAAM,UAA8B,CAAC;AACrC,UAAIE;AACJ,UAAI,YAAY;AAChB,YAAM,YAAY,IAAI,UAAU;AAEhC,YAAM,UAAU,OAAO,kBAA0B;AAC/C,YAAI,SAAS,iBAAiB,GAAG;AAC/B,UAAAA,iBAAgB,KAAK,IAAI;AACzB,gBAAM,SAASA,eAAc,gBAAgB,SAAS,iBAAiB,KAAK,IAAI;AAChF,cAAI,SAAS,EAAG,OAAM,MAAM,MAAM;AAAA,QACpC;AACA,cAAM,OAAO,SAAS,aAAa;AACnC,cAAM,SAAS,MAAM,cAAc,KAAK,MAAM,aAAa,eAAe,eAAe,KAAK,OAAO,SAAS;AAC9G,iBAAS,QAAQ,EAAE,YAAY,SAAS,QAAQ,aAAa,YAAY,KAAK,CAAC;AAC/E,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAEA,YAAM,SAAS,YAAY;AACzB,eAAO,YAAY,SAAS,QAAQ;AAClC,gBAAM,QAAQ;AACd,gBAAM,QAAQ,KAAK;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,SAAS,YAAY,GAAG,MAAM,OAAO,CAAC,CAAC;AAC9E,cAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAEhD,YAAMC,MAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AACzD,cAAQ,IAAI,WAAWA,GAAE,IAAI,QAAQ,MAAM;AAAA,CAAe;AAC1D,yBAAmB,KAAK,EAAE,aAAa,YAAY,MAAM,QAAQ,CAAC;AAClE;AAAA,IACF;AAKA,QAAI;AACJ,UAAM,OAAO,YAAY,OAAO,eAAe,OAAO,YAAY,IAAI;AAEtE,UAAM,SAAS,UAAM,yBAAU,QAAQ;AAAA,MACrC,eAAe,OAAO;AAAA,MACtB;AAAA,MACA,iBAAiB,YAAY;AAAA,MAC7B,aAAa,SAAS;AAAA,MACtB,MAAM,OAAO,QAA0B;AAGrC,cAAM,gBAAgB,IAAI,YAAY,IAAI,WAAW,UAAU;AAC/D,YAAI,SAAS,iBAAiB,GAAG;AAC/B,0BAAgB,KAAK,IAAI;AACzB,gBAAM,SAAS,cAAc,gBAAgB,SAAS,iBAAiB,KAAK,IAAI;AAChF,cAAI,SAAS,EAAG,OAAM,MAAM,MAAM;AAAA,QACpC;AACA,cAAM,OAAO,SAAS,aAAa;AAQnC,YAAI,KAAK,MAAO,KAAI,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC;AACjD,YAAI;AACF,gBAAM,aAAa,MAAM,KAAK,KAAK;AAAA,YACjC;AAAA,YACA,WAAW;AAAA,YACX,OAAO,KAAK;AAAA,YACZ,MAAM,CAAC,MAAM,IAAI,YAAY,kBAAkB,IAAI,MAAM,MAAM,IAAI,OAAO;AAAA,YAC1E,SAAS,IAAI;AAAA,YACb,KAAK,IAAI;AAAA,UACX,CAAC;AACD,iBAAO,YAAY;AAAA,QACrB,SAAS,OAAO;AAGd,cAAI,YAAY,KAAK,KAAK,MAAM,KAAM,KAAI,QAAQ,MAAM,IAAI;AAC5D,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,UAAU,CAAC,WAAW,SAAS,QAAQ,EAAE,YAAY,SAAS,QAAQ,aAAa,YAAY,KAAK,CAAC;AAAA,IACvG,CAAC;AAED,QAAI,CAAC,OAAO,YAAY;AACtB,cAAQ,MAAM,wCAAwC,KAAK,0CAAqC;AAChG,yBAAmB,KAAK,EAAE,aAAa,YAAY,MAAM,SAAS,OAAO,WAAW,CAAC,EAAE,CAAC;AACxF;AAAA,IACF;AAEA,UAAM,KAAK,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAChE,YAAQ,IAAI,WAAW,EAAE,IAAI,OAAO,QAAQ,MAAM;AAAA,CAAe;AACjE,uBAAmB,KAAK,EAAE,aAAa,YAAY,MAAM,SAAS,OAAO,QAAQ,CAAC;AAAA,EACpF;AAEA,SAAO;AACT;AAQA,eAAe,kBACb,QACA,UACA,WACA,UACA,QACA,OACA,SACA,QACA,OACA,SACA,OACA,UACA,WAAoB,OACW;AAC/B,QAAM,YAAY,oBAAI,IAAsC;AAC5D,QAAM,aAAa,oBAAI,IAAuB;AAC9C,QAAM,SAAS,oBAAI,IAAqB;AACxC,QAAM,uBAAuB,oBAAI,IAAgC;AAUjE,MAAI;AACJ,QAAM,iBAAiD,CAAC;AAExD,aAAW,eAAe,WAAW;AACnC,eAAW,IAAI,YAAY,MAAM,IAAI,UAAU,CAAC;AAChD,WAAO,IAAI,YAAY,MAAM,KAAK;AAClC,yBAAqB,IAAI,YAAY,MAAM,CAAC,CAAC;AAC7C,QAAI,YAAY,CAAC,QAAQ;AACvB,gBAAU,IAAI,YAAY,MAAM,IAAI;AACpC;AAAA,IACF;AAKA,UAAM,OAAO,YAAY,OAAO,eAAe,OAAO,YAAY,MAAM;AAAA,MACtE,aAAa;AAAA,MACb,mBAAmB,SAAS;AAAA,IAC9B,CAAC;AACD,QAAI,WAAqC;AACzC,QAAI;AACF,iBAAW,MAAM,gCAAkB,MAAM;AAAA,QACvC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,OAAO;AAAA,QACtB;AAAA,QACA,iBAAiB,YAAY;AAAA,QAC7B,aAAa;AAAA,QACb,YAAY,QAAQ,IAAI,YAAY;AAAA,MACtC,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ,KAAK,KAAK,YAAY,IAAI,4BAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,8CAAyC;AAAA,IAC/J;AACA,QAAI,CAAC,UAAU;AACb,cAAQ,KAAK,KAAK,YAAY,IAAI,gFAA2E;AAAA,IAC/G;AACA,cAAU,IAAI,YAAY,MAAM,QAAQ;AAIxC,QAAI,YAAY,CAAC,kBAAkB;AACjC,6BAAmB,4CAA6B;AAChD,qBAAe,KAAK,MAAM,iBAAiB,OAAO,CAAC;AAAA,IACrD;AAAA,EACF;AAEA,UAAQ,IAAI,gBAAgB,UAAU,MAAM,oBAAoB,SAAS,MAAM;AAAA,CAAmB;AAElG,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,UAAM,OAAO,SAAS,CAAC;AAEvB,QAAI,SAAS,iBAAiB,KAAK,IAAI,GAAG;AACxC,YAAM,MAAM,SAAS,cAAc;AAAA,IACrC;AACA,UAAM,WAAW,UAAU,IAAI,CAAC,gBAAgB,YAAY;AAC1D,YAAM,WAAW,UAAU,IAAI,YAAY,IAAI,KAAK;AACpD,YAAM,YAAY,WAAW,IAAI,YAAY,IAAI;AACjD,YAAM,SAAS,MAAM;AAAA,QACnB,KAAK;AAAA,QACL;AAAA,QACA;AAAA,SACC,UAAU,kBAAkB,KAAK;AAAA,QAClC,KAAK;AAAA,QACL;AAAA,MACF;AACA,UAAI,OAAO,WAAW,UAAW,QAAO,IAAI,YAAY,MAAM,IAAI;AAClE,eAAS,QAAQ,EAAE,YAAY,SAAS,QAAQ,aAAa,YAAY,KAAK,CAAC;AAC/E,gBAAU,aAAa,MAAM;AAC7B,YAAM,qBAAqB,qBAAqB,IAAI,YAAY,IAAI;AACpE,yBAAmB,KAAK,MAAM;AAG9B,UAAI,UAAU;AACZ,iBAAS,YAAY;AAAA,UACnB,MAAM,mBAAmB;AAAA,UACzB,UAAU;AAAA,UACV,QAAQ,mBAAmB,OAAO,CAAC,SAAS,KAAK,WAAW,SAAS,EAAE;AAAA,UACvE,OAAO,SAAS;AAAA,QAClB,CAAC;AACD,cAAM,SAAS,UAAU;AAAA,MAC3B;AAAA,IACF,CAAC;AACD,UAAM,mBAAmB,UAAU,SAAS,WAAW;AAKvD,QAAI,iBAAkB,gBAAe,KAAK,MAAM,iBAAiB,OAAO,CAAC;AAAA,EAC3E;AAMA,MAAI,iBAAkB,gBAAe,KAAK,MAAM,iBAAiB,OAAO,CAAC;AACzE,oBAAkB,KAAK;AAMvB,QAAM,kBAAkB,UAAU,IAAI,CAAC,MAAM,UAAU,IAAI,EAAE,IAAI,CAAC,EAAE,KAAK,CAAC,MAA8B,QAAQ,CAAC,CAAC;AAClH,MAAI,mBAAmB,eAAe,SAAS,GAAG;AAChD,UAAM,gBACH,eAAe;AAAA,MACd,MAAM;AAAA,MACN,aAAa;AAAA,MACb,MAAM;AAAA,MACN,UAAU,EAAE,OAAO,kBAAkB,cAAc,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE;AAAA,MAChF,MAAM,eAAe,IAAI,CAAC,WAAW,KAAK,UAAU,MAAM,CAAC,EAAE,KAAK,IAAI,IAAI;AAAA,IAC5E,CAAC,EACA,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EACnB;AAEA,aAAW,eAAe,WAAW;AACnC,UAAM,WAAW,UAAU,IAAI,YAAY,IAAI,KAAK;AACpD,UAAM,YAAY,WAAW,IAAI,YAAY,IAAI;AACjD,QAAI,YAAY,CAAC,UAAU,QAAQ,GAAG;AACpC,YAAM,SACH,eAAe,EAAE,MAAM,mBAAmB,aAAa,cAAc,MAAM,cAAc,MAAM,UAAU,OAAO,EAAE,CAAC,EACnH,MAAM,MAAM;AAAA,MAAC,CAAC;AAAA,IACnB;AACA,UAAM,UAAU,OAAO,OAAO,IAAI,YAAY,IAAI,KAAK,KAAK;AAC5D,YAAQ,IAAI,KAAK,YAAY,IAAI,SAAS,OAAO,IAAI,YAAY,IAAI,IAAI,mBAAmB,EAAE,GAAG;AAAA,EACnG;AAEA,SAAO,UAAU,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,qBAAqB,IAAI,EAAE,IAAI,KAAK,CAAC,EAAE,EAAE;AACxG;AAGA,SAAS,UAAU,MAA8B,OAAmD;AAClG,QAAM,SAAS,EAAE,GAAI,QAAQ,CAAC,GAAI,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAG;AAC9D,SAAO,OAAO,KAAK,MAAM,EAAE,SAAS,IAAI,SAAS;AACnD;AAQA,eAAe,cACb,MACA,aACA,eACA,WACA,OACA,WAC2B;AAC3B,QAAM,cAAc,KAAK,IAAI;AAC7B,QAAM,SAA2B;AAAA,IAC/B;AAAA,IACA,QAAQ;AAAA,IACR,WAAW,IAAI,KAAK,WAAW,EAAE,YAAY;AAAA,EAC/C;AACA,QAAM,iBAAmC,CAAC;AAC1C,QAAM,eAA2B,CAAC;AAGlC,MAAI,aAAoC;AAExC,QAAM,MAAsB;AAAA,IAC1B;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA,MAAM,KACJ,MACA,IACA,SACgC;AAChC,YAAM,kBAAkB,KAAK,IAAI;AACjC,YAAM,aAA6B;AAAA,QACjC;AAAA,QACA,QAAQ;AAAA,QACR,WAAW,IAAI,KAAK,eAAe,EAAE,YAAY;AAAA,QACjD,aAAa,IAAI,KAAK,eAAe,EAAE,YAAY;AAAA,QACnD,WAAW;AAAA,MACb;AACA,UAAI,SAAS,gBAAgB,OAAW,YAAW,cAAc,QAAQ;AACzE,UAAI,SAAS,cAAc,OAAW,YAAW,YAAY,QAAQ;AACrE,YAAM,eAAe;AACrB,mBAAa;AACb,UAAI;AACF,cAAMC,UAAS,MAAM,mBAAsB,MAAM,IAAI,OAAO;AAC5D,cAAM,UACJ,SAAS,kBAAkB,SAAS,CAAC,MAAM,QAAQA,OAAM,KAAK,cAAcA,OAAM,IAC7EA,UACD,CAAC;AACP,kBAAU,KAAK,WAAW,MAAM,OAAO;AACvC,eAAOA;AAAA,MACT,SAAS,OAAO;AACd,mBAAW,SAAS;AACpB,mBAAW,YAAY,YAAY,KAAK,IAAI,MAAM,QAAQ,MAAM,OAAO,aAAa,KAAK;AACzF,kBAAU,KAAK,WAAW,MAAM,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE,CAAC;AACjG,cAAM;AAAA,MACR,UAAE;AACA,qBAAa;AACb,mBAAW,eAAc,oBAAI,KAAK,GAAE,YAAY;AAChD,mBAAW,YAAY,KAAK,IAAI,IAAI;AACpC,uBAAe,KAAK,UAAU;AAAA,MAChC;AAAA,IACF;AAAA,IACA,QAAQ,MAAM;AACZ,UAAI,YAAY;AACd,mBAAW,OAAO,EAAE,GAAI,WAAW,QAAQ,CAAC,GAAI,GAAG,KAAK;AAAA,MAC1D,OAAO;AACL,eAAO,OAAO,cAAc,IAAI;AAAA,MAClC;AAAA,IACF;AAAA,IACA,IAAI,SAAS,eAAe;AAC1B,gBAAU,KAAK,SAAS,SAAS,KAAK,OAAO,IAAI,aAAa;AAAA,IAChE;AAAA,EACF;AAEA,MAAI,SAA4B;AAChC,MAAI;AACF,aAAS,MAAM,KAAK,GAAG;AACvB,WAAO,OAAO,UAAU,EAAE,GAAG,cAAc,GAAI,QAAQ,QAAQ,CAAC,EAAG,GAAG,KAAK;AAAA,EAC7E,SAAS,OAAO;AACd,WAAO,SAAS;AAChB,QAAI,YAAY,KAAK,GAAG;AACtB,aAAO,YAAY,MAAM,QAAQ,MAAM;AACvC,aAAO,OAAO,UAAU,EAAE,GAAG,cAAc,GAAI,MAAM,QAAQ,CAAC,EAAG,GAAG,KAAK;AACzE,UAAI,MAAM,OAAO,OAAQ,gBAAe,KAAK,GAAG,MAAM,KAAK;AAAA,IAC7D,OAAO;AACL,aAAO,YAAY,aAAa,KAAK;AACrC,aAAO,OAAO;AAAA,QACZ,EAAE,GAAG,cAAc,cAAc,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAAA,QACxF;AAAA,MACF;AAAA,IACF;AAAA,EACF,UAAE;AACA,UAAM,QAAQ,KAAK,IAAI;AACvB,WAAO,cAAc,IAAI,KAAK,KAAK,EAAE,YAAY;AACjD,WAAO,YACL,OAAO,WAAW,aAAa,UAAU,OAAO,OAAO,cAAc,WACjE,OAAO,YACP,QAAQ;AACd,UAAM,YAAY,OAAO,WAAW,aAAa,QAAQ,QAAQ,OAAO,QAAQ,CAAC;AACjF,UAAM,WAAW,CAAC,GAAG,gBAAgB,GAAG,SAAS;AAGjD,QAAI,SAAS,WAAW,GAAG;AACzB,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,QAAQ,OAAO,WAAW,YAAY,YAAY;AAAA,QAClD,WAAW,OAAO;AAAA,QAClB,aAAa,OAAO;AAAA,QACpB,WAAW,OAAO;AAAA,QAClB,WAAW,OAAO,aAAa;AAAA,QAC/B,MAAM,OAAO,KAAK,YAAY,EAAE,SAAS,IAAI,EAAE,GAAG,aAAa,IAAI;AAAA,MACrE,CAAC;AAAA,IACH;AACA,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;;;AGplCA,uBAAwB;AACxB,sBAA8B;AAC9B,IAAAC,cAAsC;AAMtC,IAAM,QACJ;AAaF,SAAS,kBAAkB,OAA0C;AACnE,MAAI,OAAO,UAAU,YAAY,UAAU,KAAM,QAAO;AACxD,QAAM,YAAY;AAClB,SAAO,OAAO,UAAU,kBAAkB,YAAY,MAAM,QAAQ,UAAU,YAAY;AAC5F;AAOA,eAAsB,iBAAiB,MAA+B;AACpE,QAAM,CAAC,SAAS,GAAG,IAAI,IAAI;AAE3B,QAAM,CAAC,MAAM,GAAG,KAAK,IAAI;AACzB,MAAI,YAAY,SAAS,CAAC,QAAQ,KAAK,WAAW,GAAG,EAAG,OAAM,IAAI,MAAM,KAAK;AAE7E,QAAM,MAAO,MAAM,WAAO,mCAAc,0BAAQ,QAAQ,IAAI,GAAG,IAAI,CAAC,EAAE;AACtE,QAAM,SAAS,IAAI;AACnB,QAAM,OAAO,IAAI,QAAQ,IAAI;AAE7B,MAAI,CAAC,kBAAkB,MAAM,GAAG;AAC9B,UAAM,IAAI,MAAM,GAAG,IAAI,mFAAmF;AAAA,EAC5G;AACA,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,IAAI,MAAM,GAAG,IAAI,kDAAkD;AAAA,EAC3E;AAEA,QAAM,aAAa,QAA4C,MAAwC,KAAK;AAC9G;AAGA,eAAsB,IAAI,MAA+B;AACvD,MAAI,KAAK,CAAC,MAAM,OAAO;AACrB,eAAO,YAAAC,KAAe,IAAI;AAAA,EAC5B;AAEA,MAAI;AACF,UAAM,iBAAiB,IAAI;AAG3B,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,KAAK;AACZ,QAAI,eAAe,8BAA8B;AAC/C,cAAQ,IAAI,IAAI,OAAO;AACvB,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,YAAQ,MAAM,qBAAqB,eAAe,QAAQ,IAAI,UAAU,GAAG;AAC3E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF;;;ANtFO,IAAM,0BAA0B;","names":["resolve","run","os","rampStartMs","ok","result","import_cli","runPlatformCli"]}