@omni-oss/task-bench 0.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +328 -0
  2. package/dist/bench/index.d.ts +82 -0
  3. package/dist/bench/index.d.ts.map +1 -0
  4. package/dist/bench/install.d.ts +5 -0
  5. package/dist/bench/install.d.ts.map +1 -0
  6. package/dist/bench/report.d.ts +9 -0
  7. package/dist/bench/report.d.ts.map +1 -0
  8. package/dist/bench/stats.d.ts +12 -0
  9. package/dist/bench/stats.d.ts.map +1 -0
  10. package/dist/cli/index.d.ts +3 -0
  11. package/dist/cli/index.d.ts.map +1 -0
  12. package/dist/config.d.ts +91 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/generate/index.d.ts +19 -0
  15. package/dist/generate/index.d.ts.map +1 -0
  16. package/dist/generate/templates.d.ts +20 -0
  17. package/dist/generate/templates.d.ts.map +1 -0
  18. package/dist/graph.d.ts +21 -0
  19. package/dist/graph.d.ts.map +1 -0
  20. package/dist/index.d.ts +16 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.mjs +2 -0
  23. package/dist/src-D3XyMXAu.mjs +1167 -0
  24. package/dist/suite/index.d.ts +49 -0
  25. package/dist/suite/index.d.ts.map +1 -0
  26. package/dist/suite/preset.d.ts +93 -0
  27. package/dist/suite/preset.d.ts.map +1 -0
  28. package/dist/suite/report.d.ts +7 -0
  29. package/dist/suite/report.d.ts.map +1 -0
  30. package/dist/task-bench-cli.mjs +107 -0
  31. package/dist/tools/index.d.ts +18 -0
  32. package/dist/tools/index.d.ts.map +1 -0
  33. package/dist/tools/moon.d.ts +10 -0
  34. package/dist/tools/moon.d.ts.map +1 -0
  35. package/dist/tools/nx.d.ts +7 -0
  36. package/dist/tools/nx.d.ts.map +1 -0
  37. package/dist/tools/omni.d.ts +7 -0
  38. package/dist/tools/omni.d.ts.map +1 -0
  39. package/dist/tools/turbo.d.ts +5 -0
  40. package/dist/tools/turbo.d.ts.map +1 -0
  41. package/dist/tools/types.d.ts +77 -0
  42. package/dist/tools/types.d.ts.map +1 -0
  43. package/package.json +41 -0
  44. package/project.omni.yaml +33 -0
  45. package/src/bench/index.ts +323 -0
  46. package/src/bench/install.ts +12 -0
  47. package/src/bench/report.ts +142 -0
  48. package/src/bench/stats.spec.ts +35 -0
  49. package/src/bench/stats.ts +38 -0
  50. package/src/cli/index.ts +410 -0
  51. package/src/config.ts +138 -0
  52. package/src/generate/index.ts +215 -0
  53. package/src/generate/templates.ts +87 -0
  54. package/src/graph.spec.ts +119 -0
  55. package/src/graph.ts +120 -0
  56. package/src/index.ts +31 -0
  57. package/src/suite/index.ts +113 -0
  58. package/src/suite/preset.spec.ts +95 -0
  59. package/src/suite/preset.ts +253 -0
  60. package/src/suite/report.ts +135 -0
  61. package/src/tools/adapters.spec.ts +95 -0
  62. package/src/tools/config.spec.ts +73 -0
  63. package/src/tools/index.ts +76 -0
  64. package/src/tools/moon.ts +106 -0
  65. package/src/tools/nx.ts +106 -0
  66. package/src/tools/omni.ts +96 -0
  67. package/src/tools/turbo.ts +78 -0
  68. package/src/tools/types.ts +116 -0
  69. package/tsconfig.json +4 -0
  70. package/tsconfig.project.json +6 -0
  71. package/tsconfig.types.json +4 -0
  72. package/vite.config.ts +29 -0
  73. package/vitest.config.unit.ts +13 -0
@@ -0,0 +1,49 @@
1
+ import { BenchEvent, BenchmarkResult } from '../bench';
2
+ import { HarnessConfig } from '../config';
3
+ import { RunOptions, SuiteConfig } from './preset';
4
+ export interface SuiteScenarioResult {
5
+ name: string;
6
+ description?: string | undefined;
7
+ config: HarnessConfig;
8
+ run: RunOptions;
9
+ result: BenchmarkResult;
10
+ }
11
+ export interface SuiteResult {
12
+ name: string;
13
+ description?: string | undefined;
14
+ generatedAt: string;
15
+ scenarios: SuiteScenarioResult[];
16
+ taskBenchVersion: string;
17
+ }
18
+ export type SuiteEvent = {
19
+ kind: "scenario-start";
20
+ name: string;
21
+ index: number;
22
+ total: number;
23
+ } | {
24
+ kind: "scenario-done";
25
+ name: string;
26
+ index: number;
27
+ total: number;
28
+ } | {
29
+ kind: "bench";
30
+ name: string;
31
+ event: BenchEvent;
32
+ };
33
+ export interface RunSuiteOptions {
34
+ /** Base directory under which each scenario workspace is generated. */
35
+ workdir: string;
36
+ /** Run `bun install` in each generated workspace (default true). */
37
+ install?: boolean | undefined;
38
+ /** Keep generated workspaces on disk instead of removing them (default false). */
39
+ keep?: boolean | undefined;
40
+ /** Global run-option overrides applied to every scenario. */
41
+ overrides?: Partial<RunOptions> | undefined;
42
+ onEvent?: ((event: SuiteEvent) => void) | undefined;
43
+ }
44
+ /**
45
+ * Run every scenario in a suite: generate a workspace, install, benchmark, and
46
+ * collect the results. Workspaces are removed afterwards unless `keep` is set.
47
+ */
48
+ export declare function runSuite(suite: SuiteConfig, options: RunSuiteOptions): Promise<SuiteResult>;
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/suite/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,eAAe,EAAgB,MAAM,UAAU,CAAC;AAE/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,KAAK,UAAU,EAAmB,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAE9E,MAAM,WAAW,mBAAmB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;IAChB,MAAM,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,mBAAmB,EAAE,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,UAAU,GAChB;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,eAAe;IAC5B,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,kFAAkF;IAClF,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,6DAA6D;IAC7D,SAAS,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CACvD;AAED;;;GAGG;AACH,wBAAsB,QAAQ,CAC1B,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,eAAe,GACzB,OAAO,CAAC,WAAW,CAAC,CA+DtB"}
@@ -0,0 +1,93 @@
1
+ import { z } from 'zod';
2
+ import { HarnessConfig } from '../config';
3
+ /** Per-scenario benchmark run options (serializable subset of RunBenchmarkOptions). */
4
+ export declare const RunOptionsSchema: z.ZodDefault<z.ZodObject<{
5
+ tools: z.ZodOptional<z.ZodArray<z.ZodEnum<{
6
+ omni: "omni";
7
+ turbo: "turbo";
8
+ nx: "nx";
9
+ moon: "moon";
10
+ }>>>;
11
+ task: z.ZodOptional<z.ZodString>;
12
+ coldRuns: z.ZodOptional<z.ZodNumber>;
13
+ warmRuns: z.ZodOptional<z.ZodNumber>;
14
+ concurrency: z.ZodOptional<z.ZodNumber>;
15
+ daemon: z.ZodOptional<z.ZodBoolean>;
16
+ }, z.core.$strip>>;
17
+ export type RunOptions = z.infer<typeof RunOptionsSchema>;
18
+ export declare const ScenarioSchema: z.ZodObject<{
19
+ name: z.ZodString;
20
+ description: z.ZodOptional<z.ZodString>;
21
+ config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
22
+ run: z.ZodDefault<z.ZodObject<{
23
+ tools: z.ZodOptional<z.ZodArray<z.ZodEnum<{
24
+ omni: "omni";
25
+ turbo: "turbo";
26
+ nx: "nx";
27
+ moon: "moon";
28
+ }>>>;
29
+ task: z.ZodOptional<z.ZodString>;
30
+ coldRuns: z.ZodOptional<z.ZodNumber>;
31
+ warmRuns: z.ZodOptional<z.ZodNumber>;
32
+ concurrency: z.ZodOptional<z.ZodNumber>;
33
+ daemon: z.ZodOptional<z.ZodBoolean>;
34
+ }, z.core.$strip>>;
35
+ }, z.core.$strip>;
36
+ export declare const SuiteSchema: z.ZodObject<{
37
+ name: z.ZodDefault<z.ZodString>;
38
+ description: z.ZodOptional<z.ZodString>;
39
+ defaults: z.ZodPrefault<z.ZodObject<{
40
+ config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
41
+ run: z.ZodDefault<z.ZodObject<{
42
+ tools: z.ZodOptional<z.ZodArray<z.ZodEnum<{
43
+ omni: "omni";
44
+ turbo: "turbo";
45
+ nx: "nx";
46
+ moon: "moon";
47
+ }>>>;
48
+ task: z.ZodOptional<z.ZodString>;
49
+ coldRuns: z.ZodOptional<z.ZodNumber>;
50
+ warmRuns: z.ZodOptional<z.ZodNumber>;
51
+ concurrency: z.ZodOptional<z.ZodNumber>;
52
+ daemon: z.ZodOptional<z.ZodBoolean>;
53
+ }, z.core.$strip>>;
54
+ }, z.core.$strip>>;
55
+ scenarios: z.ZodArray<z.ZodObject<{
56
+ name: z.ZodString;
57
+ description: z.ZodOptional<z.ZodString>;
58
+ config: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
59
+ run: z.ZodDefault<z.ZodObject<{
60
+ tools: z.ZodOptional<z.ZodArray<z.ZodEnum<{
61
+ omni: "omni";
62
+ turbo: "turbo";
63
+ nx: "nx";
64
+ moon: "moon";
65
+ }>>>;
66
+ task: z.ZodOptional<z.ZodString>;
67
+ coldRuns: z.ZodOptional<z.ZodNumber>;
68
+ warmRuns: z.ZodOptional<z.ZodNumber>;
69
+ concurrency: z.ZodOptional<z.ZodNumber>;
70
+ daemon: z.ZodOptional<z.ZodBoolean>;
71
+ }, z.core.$strip>>;
72
+ }, z.core.$strip>>;
73
+ }, z.core.$strip>;
74
+ export type SuiteConfig = z.infer<typeof SuiteSchema>;
75
+ export type SuiteConfigInput = z.input<typeof SuiteSchema>;
76
+ export type Scenario = z.infer<typeof ScenarioSchema>;
77
+ /** Deep-merge plain objects; arrays and scalars from `override` replace `base`. */
78
+ export declare function deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown>;
79
+ export interface ResolvedScenario {
80
+ name: string;
81
+ description?: string | undefined;
82
+ config: HarnessConfig;
83
+ run: RunOptions;
84
+ }
85
+ /** Merge a scenario over suite defaults and resolve/validate its config. */
86
+ export declare function resolveScenario(suite: SuiteConfig, scenario: Scenario): ResolvedScenario;
87
+ export declare const BUILTIN_PRESETS: Record<string, SuiteConfigInput>;
88
+ export declare function listPresets(): string[];
89
+ /** Resolve a built-in preset by name, or throw with the list of valid names. */
90
+ export declare function getPreset(name: string): SuiteConfig;
91
+ /** Parse and validate a suite preset object (e.g. loaded from a JSON file). */
92
+ export declare function parseSuite(input: unknown): SuiteConfig;
93
+ //# sourceMappingURL=preset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../src/suite/preset.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACH,KAAK,aAAa,EAIrB,MAAM,WAAW,CAAC;AAEnB,uFAAuF;AACvF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;kBASb,CAAC;AAEjB,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAQ1D,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;iBAUzB,CAAC;AAEH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAUtB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AACtD,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAMtD,mFAAmF;AACnF,wBAAgB,SAAS,CACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAED,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,MAAM,EAAE,aAAa,CAAC;IACtB,GAAG,EAAE,UAAU,CAAC;CACnB;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAC3B,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,QAAQ,GACnB,gBAAgB,CAYlB;AA8HD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAO5D,CAAC;AAEF,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAQnD;AAED,+EAA+E;AAC/E,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,CAEtD"}
@@ -0,0 +1,7 @@
1
+ import { SuiteResult } from './index';
2
+ /**
3
+ * Render a full suite as Markdown: two summary matrices (warm + cold median per
4
+ * tool per scenario) followed by the detailed per-scenario report tables.
5
+ */
6
+ export declare function formatSuiteMarkdown(suite: SuiteResult): string;
7
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/suite/report.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAuB,MAAM,SAAS,CAAC;AAqDhE;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA0E9D"}
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ import { F as e, I as t, N as n, P as r, T as i, _ as a, c as o, f as s, h as c, k as l, l as u, m as d, n as f, p, t as m, u as h } from "./src-D3XyMXAu.mjs";
3
+ import { readFileSync as g, writeFileSync as _ } from "node:fs";
4
+ import { tmpdir as v } from "node:os";
5
+ import { join as y, resolve as b } from "node:path";
6
+ import { Command as x, Option as S } from "@commander-js/extra-typings";
7
+ //#region src/cli/index.ts
8
+ var C = new x();
9
+ C.name(e).version(t).description(r);
10
+ var w = (e) => {
11
+ let t = Number.parseInt(e, 10);
12
+ if (Number.isNaN(t)) throw Error(`expected an integer, got "${e}"`);
13
+ return t;
14
+ }, T = (e) => {
15
+ let t = Number.parseFloat(e);
16
+ if (Number.isNaN(t)) throw Error(`expected a number, got "${e}"`);
17
+ return t;
18
+ }, E = (e) => e.split(",").map((e) => {
19
+ let t = e.trim();
20
+ if (!l.includes(t)) throw Error(`unknown tool "${t}" (allowed: ${l.join(", ")})`);
21
+ return t;
22
+ });
23
+ function D(e) {
24
+ let t = e.config ? JSON.parse(g(e.config, "utf8")) : {}, n = { ...t };
25
+ e.seed !== void 0 && (n.seed = e.seed), e.projects !== void 0 && (n.projects = e.projects), e.tasks !== void 0 && (n.tasksPerProject = e.tasks), e.tools !== void 0 && (n.tools = e.tools);
26
+ let r = { ...t.dependency ?? {} };
27
+ e.strategy !== void 0 && (r.strategy = e.strategy), e.layers !== void 0 && (r.layers = e.layers), e.fanout !== void 0 && (r.fanout = e.fanout), e.edgeProbability !== void 0 && (r.edgeProbability = e.edgeProbability), Object.keys(r).length && (n.dependency = r);
28
+ let i = { ...t.task ?? {} };
29
+ e.logLines !== void 0 && (i.logLines = e.logLines), e.work !== void 0 && (i.workIterations = e.work), e.outputFiles !== void 0 && (i.outputFiles = e.outputFiles), e.chain !== void 0 && (i.chainWithinProject = e.chain), e.fanUpstream !== void 0 && (i.fanUpstream = e.fanUpstream), Object.keys(i).length && (n.task = i);
30
+ let a = { ...t.versions ?? {} };
31
+ return e.turboVersion !== void 0 && (a.turbo = e.turboVersion), e.nxVersion !== void 0 && (a.nx = e.nxVersion), e.moonVersion !== void 0 && (a.moon = e.moonVersion), e.bunVersion !== void 0 && (a.bun = e.bunVersion), Object.keys(a).length && (n.versions = a), n;
32
+ }
33
+ function O(e) {
34
+ return e.option("--config <file>", "Base config JSON file to extend.").option("--seed <n>", "Deterministic graph seed.", w).option("--projects <n>", "Number of projects.", w).option("--tasks <n>", "Tasks per project.", w).addOption(new S("--strategy <name>", "Dependency graph strategy.").choices(i)).option("--layers <n>", "Layers for the `layered` strategy.", w).option("--fanout <n>", "Max upstream deps per project.", w).option("--edge-probability <p>", "Edge probability for `random`.", T).option("--log-lines <n>", "Log lines printed per task.", w).option("--work <n>", "CPU work iterations per task.", w).option("--output-files <n>", "Output files per task.", w).option("--tools <list>", "Comma-separated tools (omni,turbo,nx,moon).", E).option("--turbo-version <semver>", "Turbo version to install.").option("--nx-version <semver>", "Nx version to install.").option("--moon-version <semver>", "moon (@moonrepo/cli) version to install.").option("--bun-version <semver>", "bun version for packageManager.").option("--no-chain", "Disable intra-project task chaining.").option("--no-fan-upstream", "Disable upstream (^) task dependencies.");
35
+ }
36
+ function k() {
37
+ return (e) => {
38
+ if (e.kind === "tool-start") process.stderr.write(`\n▶ ${e.tool}\n`);
39
+ else if (e.kind === "tool-error") process.stderr.write(` ✖ ${e.tool}: ${e.error}\n`);
40
+ else if (e.kind === "tool-unsuccessful") process.stderr.write(` ✖ ${e.tool}: exit ${e.sample.exitCode}\n`), e.sample.stdout && process.stderr.write(` === stdout ===\n${e.sample.stdout}\n`), e.sample.stderr && process.stderr.write(` === stderr ===\n${e.sample.stderr}\n`);
41
+ else {
42
+ let t = e.sample.ok ? "ok" : `exit ${e.sample.exitCode}`;
43
+ process.stderr.write(` ${e.scenario} ${e.run}/${e.total}: ${a(e.sample.durationMs)} (ran ${e.sample.executed} tasks, ${t})\n`);
44
+ }
45
+ };
46
+ }
47
+ function A(e, t) {
48
+ e && (_(e, `${JSON.stringify(t, null, 2)}\n`), process.stderr.write(`\nWrote results to ${e}\n`));
49
+ }
50
+ O(C.command("generate").alias("gen").description("Generate a benchmark workspace at the given root dir.").requiredOption("-o, --out <dir>", "Root dir to generate the workspace into.")).action(async (e) => {
51
+ let t = b(e.out), n = await s(t, D(e));
52
+ process.stderr.write(`Generated ${n.projects.length} projects (${n.files.length} files) at ${t}\nTools: ${n.config.tools.join(", ")}\n`);
53
+ }), C.command("run").description("Benchmark an already-generated workspace.").requiredOption("-d, --dir <dir>", "Root dir of a generated workspace.").option("--tools <list>", "Comma-separated tools to benchmark.", E).option("--task <name>", "Task to run (defaults to the last task).").option("--cold-runs <n>", "Cold (uncached) runs per tool.", w, 3).option("--warm-runs <n>", "Warm (cached) runs per tool.", w, 5).option("--concurrency <n>", "Max parallel tasks, applied identically to all tools (default: CPU count).", w).option("--no-daemon", "Disable each tool's persistent daemon (turbo, nx).").option("--json <file>", "Write full results as JSON to this file.").action(async (e) => {
54
+ let t = await c(b(e.dir), {
55
+ tools: e.tools,
56
+ task: e.task,
57
+ concurrency: e.concurrency,
58
+ daemon: e.daemon,
59
+ coldRuns: e.coldRuns,
60
+ warmRuns: e.warmRuns,
61
+ onEvent: k()
62
+ });
63
+ process.stdout.write(p(t)), A(e.json, t);
64
+ }), O(C.command("bench").description("Generate, install, and benchmark in one step.").requiredOption("-o, --out <dir>", "Root dir to generate the workspace into.").option("--no-install", "Skip `bun install` in the generated workspace.").option("--task <name>", "Task to run (defaults to the last task).").option("--cold-runs <n>", "Cold (uncached) runs per tool.", w, 3).option("--warm-runs <n>", "Warm (cached) runs per tool.", w, 5).option("--concurrency <n>", "Max parallel tasks, applied identically to all tools (default: CPU count).", w).option("--no-daemon", "Disable each tool's persistent daemon (turbo, nx).").option("--json <file>", "Write full results as JSON to this file.")).action(async (e) => {
65
+ let t = b(e.out), n = await s(t, D(e));
66
+ process.stderr.write(`Generated ${n.projects.length} projects at ${t}\n`), e.install !== !1 && (process.stderr.write("Installing dependencies (bun install)...\n"), await d(t));
67
+ let r = await c(t, {
68
+ task: e.task,
69
+ coldRuns: e.coldRuns,
70
+ warmRuns: e.warmRuns,
71
+ concurrency: e.concurrency,
72
+ daemon: e.daemon,
73
+ onEvent: k()
74
+ });
75
+ process.stdout.write(p(r)), A(e.json, r);
76
+ }), O(C.command("inspect").description("Resolve a config and print the derived graph summary.")).action((e) => {
77
+ let t = n(D(e));
78
+ process.stdout.write(`${JSON.stringify(t, null, 2)}\n`);
79
+ });
80
+ function j() {
81
+ let e = k();
82
+ return (t) => {
83
+ t.kind === "scenario-start" ? process.stderr.write(`\n=== [${t.index + 1}/${t.total}] ${t.name} ===\n`) : t.kind === "bench" && e(t.event);
84
+ };
85
+ }
86
+ C.command("suite").description("Run a preset (or JSON file) of benchmark scenarios and summarize them.").option("-p, --preset <name>", "Built-in preset name.").option("-f, --file <path>", "Path to a JSON suite preset file.").option("-o, --out <dir>", "Working dir for generated workspaces.").option("--json <file>", "Write aggregated results as JSON to this file.").option("--md <file>", "Write a human-readable Markdown report to this file.").option("--tools <list>", "Override tools for every scenario.", E).option("--cold-runs <n>", "Override cold runs for every scenario.", w).option("--warm-runs <n>", "Override warm runs for every scenario.", w).option("--concurrency <n>", "Override concurrency for every scenario.", w).option("--no-install", "Skip `bun install` in generated workspaces.").option("--keep", "Keep generated workspaces instead of removing them.").option("--list", "List the built-in presets and exit.").action(async (e) => {
87
+ if (e.list) {
88
+ process.stdout.write(`Available presets:\n${u().map((e) => ` - ${e}`).join("\n")}\n`);
89
+ return;
90
+ }
91
+ let t = e.file ? h(JSON.parse(g(e.file, "utf8"))) : o(e.preset ?? "quick"), n = b(e.out ?? y(v(), "task-bench-suite"));
92
+ process.stderr.write(`Running suite "${t.name}" (${t.scenarios.length} scenarios) in ${n}\n`);
93
+ let r = {
94
+ ...e.tools ? { tools: e.tools } : {},
95
+ ...e.coldRuns === void 0 ? {} : { coldRuns: e.coldRuns },
96
+ ...e.warmRuns === void 0 ? {} : { warmRuns: e.warmRuns },
97
+ ...e.concurrency === void 0 ? {} : { concurrency: e.concurrency }
98
+ }, i = await f(t, {
99
+ workdir: n,
100
+ install: e.install,
101
+ keep: e.keep,
102
+ overrides: r,
103
+ onEvent: j()
104
+ }), a = m(i);
105
+ process.stdout.write(`\n${a}\n`), e.md && (_(e.md, `${a}\n`), process.stderr.write(`\nWrote Markdown report to ${e.md}\n`)), e.json && (_(e.json, `${JSON.stringify(i, null, 2)}\n`), process.stderr.write(`Wrote JSON results to ${e.json}\n`));
106
+ }), C.parseAsync();
107
+ //#endregion
@@ -0,0 +1,18 @@
1
+ import { HarnessConfig, Tool } from '../config';
2
+ import { ToolAdapter } from './types';
3
+ export declare function getAdapter(tool: Tool): ToolAdapter;
4
+ export declare function getAdapters(tools: Tool[]): ToolAdapter[];
5
+ /** Throw if `version` does not satisfy any of the adapter's supported ranges. */
6
+ export declare function assertSupportedVersion(adapter: ToolAdapter, version: string): void;
7
+ /**
8
+ * Resolve each enabled tool's version (pinned via config, or detected for
9
+ * external tools) and validate it against the adapter's supported ranges.
10
+ * Throws on the first unsupported version. Returns a map of tool -> version.
11
+ */
12
+ export declare function resolveToolVersions(config: HarnessConfig, rootDir: string, tools?: Tool[]): Promise<Map<Tool, string | null>>;
13
+ export { moonAdapter, moonProjectConfig, moonTaskDependencies, moonToolchainConfig, moonWorkspaceConfig, } from './moon';
14
+ export { nxAdapter, nxProjectConfig, nxRootConfig } from './nx';
15
+ export { omniAdapter, omniProjectConfig, omniWorkspaceConfig } from './omni';
16
+ export { turboAdapter, turboRootConfig } from './turbo';
17
+ export * from './types';
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAKrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAS3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,WAAW,CAElD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,WAAW,EAAE,CAExD;AAED,iFAAiF;AACjF,wBAAgB,sBAAsB,CAClC,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,MAAM,GAChB,IAAI,CAWN;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CACrC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,IAAI,EAAiB,GAC7B,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAcnC;AAED,OAAO,EACH,WAAW,EACX,iBAAiB,EACjB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,GACtB,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACxD,cAAc,SAAS,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { HarnessConfig } from '../config';
2
+ import { ProjectNode } from '../graph';
3
+ import { ToolAdapter } from './types';
4
+ /** moon dependency edges for task index `k`, using moon's target syntax. */
5
+ export declare function moonTaskDependencies(config: HarnessConfig, k: number): string[];
6
+ export declare function moonWorkspaceConfig(): string;
7
+ export declare function moonToolchainConfig(): string;
8
+ export declare function moonProjectConfig(config: HarnessConfig, project: ProjectNode, projects: ProjectNode[]): string;
9
+ export declare const moonAdapter: ToolAdapter;
10
+ //# sourceMappingURL=moon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moon.d.ts","sourceRoot":"","sources":["../../src/tools/moon.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,KAAK,WAAW,EAAa,MAAM,UAAU,CAAC;AACvD,OAAO,EAKH,KAAK,WAAW,EAEnB,MAAM,SAAS,CAAC;AAMjB,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAChC,MAAM,EAAE,aAAa,EACrB,CAAC,EAAE,MAAM,GACV,MAAM,EAAE,CAKV;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAK5C;AAED,wBAAgB,mBAAmB,IAAI,MAAM,CAI5C;AAED,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,GACxB,MAAM,CAwBR;AAED,eAAO,MAAM,WAAW,EAAE,WAiCzB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { HarnessConfig } from '../config';
2
+ import { ProjectNode } from '../graph';
3
+ import { ToolAdapter } from './types';
4
+ export declare function nxRootConfig(config: HarnessConfig): string;
5
+ export declare function nxProjectConfig(config: HarnessConfig, project: ProjectNode): string;
6
+ export declare const nxAdapter: ToolAdapter;
7
+ //# sourceMappingURL=nx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nx.d.ts","sourceRoot":"","sources":["../../src/tools/nx.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,KAAK,WAAW,EAAa,MAAM,UAAU,CAAC;AACvD,OAAO,EAIH,KAAK,WAAW,EAGnB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAsB1D;AAED,wBAAgB,eAAe,CAC3B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,WAAW,GACrB,MAAM,CAiBR;AAED,eAAO,MAAM,SAAS,EAAE,WA+CvB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { HarnessConfig } from '../config';
2
+ import { ProjectNode } from '../graph';
3
+ import { ToolAdapter } from './types';
4
+ export declare function omniWorkspaceConfig(): string;
5
+ export declare function omniProjectConfig(config: HarnessConfig, project: ProjectNode, projects: ProjectNode[]): string;
6
+ export declare const omniAdapter: ToolAdapter;
7
+ //# sourceMappingURL=omni.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"omni.d.ts","sourceRoot":"","sources":["../../src/tools/omni.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,KAAK,WAAW,EAAa,MAAM,UAAU,CAAC;AACvD,OAAO,EAIH,KAAK,WAAW,EAGnB,MAAM,SAAS,CAAC;AAOjB,wBAAgB,mBAAmB,IAAI,MAAM,CAG5C;AAED,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,GACxB,MAAM,CAqBR;AAED,eAAO,MAAM,WAAW,EAAE,WA2CzB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { HarnessConfig } from '../config';
2
+ import { ToolAdapter } from './types';
3
+ export declare function turboRootConfig(config: HarnessConfig): string;
4
+ export declare const turboAdapter: ToolAdapter;
5
+ //# sourceMappingURL=turbo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turbo.d.ts","sourceRoot":"","sources":["../../src/tools/turbo.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAIH,KAAK,WAAW,EAGnB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAqB7D;AAED,eAAO,MAAM,YAAY,EAAE,WAwC1B,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { HarnessConfig, Tool } from '../config';
2
+ import { ProjectNode } from '../graph';
3
+ /** Writes a workspace-relative file (creating parent dirs) and records it. */
4
+ export type WorkspaceWriter = (relPath: string, contents: string) => Promise<void>;
5
+ /** Everything a tool needs to write its configuration after generation. */
6
+ export interface GenerationContext {
7
+ /** Absolute path to the generated workspace root. */
8
+ rootDir: string;
9
+ config: HarnessConfig;
10
+ /** All generated projects, in index order. */
11
+ projects: ProjectNode[];
12
+ /** The resolved version of this tool (pinned or detected), if known. */
13
+ version: string | null;
14
+ /** Write a file into the workspace. */
15
+ write: WorkspaceWriter;
16
+ }
17
+ /** Runtime context for executing/benchmarking a tool. */
18
+ export interface ToolContext {
19
+ /** Absolute path to the generated workspace root. */
20
+ rootDir: string;
21
+ /** Workspace-relative project directories, e.g. `packages/bench-p0001`. */
22
+ projectDirs: string[];
23
+ /** Concurrency applied identically to every runner. */
24
+ concurrency: number;
25
+ /** Whether the tool's persistent daemon (if any) is allowed. */
26
+ daemon: boolean;
27
+ }
28
+ export interface RunInvocation {
29
+ file: string;
30
+ args: string[];
31
+ }
32
+ /**
33
+ * A self-contained integration for one task runner. Each adapter owns:
34
+ * - which tool versions it supports (`supportedVersions`),
35
+ * - the npm dependencies it needs (`devDependencies`),
36
+ * - how to write its own configuration (`setup`),
37
+ * - and how to run / reset / clean it up at benchmark time.
38
+ * This keeps every tool decoupled from the generator and from each other.
39
+ */
40
+ export interface ToolAdapter {
41
+ tool: Tool;
42
+ /** Whether this runner has a persistent daemon that can boost warm perf. */
43
+ hasDaemon: boolean;
44
+ /** Semver ranges of the tool version this adapter supports. */
45
+ supportedVersions: readonly string[];
46
+ /** Version pinned via config for installable tools; null for external ones. */
47
+ pinnedVersion(config: HarnessConfig): string | null;
48
+ /** Detect the installed version of an external/global tool (e.g. omni). */
49
+ detectVersion?(rootDir: string): Promise<string | null>;
50
+ /** npm devDependencies to add to the root package.json. */
51
+ devDependencies(config: HarnessConfig): Record<string, string>;
52
+ /** Derive and write this tool's config files from the generated projects. */
53
+ setup(ctx: GenerationContext): Promise<void>;
54
+ /** Command that runs `task` across every project in the workspace. */
55
+ run(task: string, ctx: ToolContext): RunInvocation;
56
+ /** Extra environment variables for each invocation (e.g. daemon toggles). */
57
+ env(ctx: ToolContext): Record<string, string>;
58
+ /** Remove caches and all task outputs. */
59
+ clearCaches(ctx: ToolContext): Promise<void>;
60
+ /** Stop the persistent daemon, if any. Used for cold runs and cleanup. */
61
+ stopDaemon(ctx: ToolContext): Promise<void>;
62
+ }
63
+ /** Resolve a locally-installed binary, falling back to the global name. */
64
+ export declare function resolveBin(rootDir: string, name: string): string;
65
+ /** Remove the `dist/` output directory of every project. */
66
+ export declare function removeDist(ctx: ToolContext): Promise<void>;
67
+ /**
68
+ * Dependency edges for task index `k`, shared by omni/turbo/nx so their graphs
69
+ * stay equivalent:
70
+ * - within-project: `t{k-1}` (if enabled and k > 0)
71
+ * - upstream: `^t{k}` (if enabled)
72
+ */
73
+ export declare function taskDependencies(config: HarnessConfig, k: number): string[];
74
+ /** Map upstream project indices to their names for a project's dependencies. */
75
+ export declare function dependencyNames(project: ProjectNode, projects: ProjectNode[]): string[];
76
+ export type { Tool };
77
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,8EAA8E;AAC9E,MAAM,MAAM,eAAe,GAAG,CAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,KACf,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,2EAA2E;AAC3E,MAAM,WAAW,iBAAiB;IAC9B,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,wEAAwE;IACxE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,uCAAuC;IACvC,KAAK,EAAE,eAAe,CAAC;CAC1B;AAED,yDAAyD;AACzD,MAAM,WAAW,WAAW;IACxB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAC;IACnB,+DAA+D;IAC/D,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IAErC,+EAA+E;IAC/E,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAAC;IACpD,2EAA2E;IAC3E,aAAa,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,2DAA2D;IAC3D,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/D,6EAA6E;IAC7E,KAAK,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7C,sEAAsE;IACtE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,aAAa,CAAC;IACnD,6EAA6E;IAC7E,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,0CAA0C;IAC1C,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,0EAA0E;IAC1E,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhE;AAED,4DAA4D;AAC5D,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAShE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAK3E;AAED,gFAAgF;AAChF,wBAAgB,eAAe,CAC3B,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,WAAW,EAAE,GACxB,MAAM,EAAE,CAEV;AAED,YAAY,EAAE,IAAI,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@omni-oss/task-bench",
3
+ "description": "Generate configurable test workspaces and benchmark omni/turbo/nx task execution performance",
4
+ "version": "0.0.0-beta.1",
5
+ "bin": "./dist/task-bench-cli.mjs",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": {
13
+ "development": "./src/index.ts",
14
+ "default": "./dist/index.mjs"
15
+ },
16
+ "require": {
17
+ "development": "./src/index.ts",
18
+ "default": "./dist/index.mjs"
19
+ }
20
+ }
21
+ },
22
+ "dependencies": {
23
+ "commander": "^14.0.3",
24
+ "@commander-js/extra-typings": "^14.0.0",
25
+ "@omni-oss/log": "^0.1.0",
26
+ "execa": "^9.6.1",
27
+ "semver": "^7.8.5",
28
+ "yaml": "^2.9.0",
29
+ "zod": "^4.4.3"
30
+ },
31
+ "devDependencies": {
32
+ "@omni-oss/tsconfig": "^0.1.1",
33
+ "@omni-oss/vite-config": "^0.2.1",
34
+ "@omni-oss/vitest-config": "^0.0.0",
35
+ "vite": "^8.0.16",
36
+ "vitest": "^4.1.8",
37
+ "@types/node": "^25.9.1",
38
+ "@types/semver": "^7.7.1",
39
+ "typescript": "^6.0.3"
40
+ }
41
+ }
@@ -0,0 +1,33 @@
1
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/omni-oss/json-schemas/refs/heads/main/project.json
2
+ name: "@omni-oss/task-bench"
3
+
4
+ extends:
5
+
6
+ - "@workspace/omni/presets/ts-vite-script.omni.yaml"
7
+
8
+
9
+ dependencies:
10
+ append:
11
+ - "@omni-oss/tsconfig"
12
+ - "@omni-oss/vite-config"
13
+ - "@omni-oss/vitest-config"
14
+
15
+ tasks:
16
+
17
+ test:unit:
18
+ enabled: true
19
+
20
+ test:integration:
21
+ enabled: false
22
+
23
+ test:
24
+ enabled: true
25
+
26
+ build:
27
+ enabled: true
28
+
29
+ publish:
30
+ enabled: true
31
+
32
+ meta:
33
+ publish: true