@polderlabs/bizar 10.17.3 → 10.19.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.
Files changed (81) hide show
  1. package/cli/bin.mjs +89 -6
  2. package/cli/commands/bench.mjs +360 -0
  3. package/cli/commands/evidence-bundles.mjs +239 -0
  4. package/cli/commands/evidence.mjs +101 -0
  5. package/cli/commands/explain-run.mjs +278 -0
  6. package/cli/commands/improve-proposal.mjs +155 -0
  7. package/cli/commands/improve.mjs +385 -0
  8. package/cli/commands/learning-behavior.mjs +200 -0
  9. package/cli/commands/model.mjs +26 -8
  10. package/cli/commands/models.mjs +66 -14
  11. package/cli/commands/objective-scheduler.mjs +609 -0
  12. package/cli/commands/release-provenance.mjs +261 -0
  13. package/cli/commands/secure-dir.mjs +81 -0
  14. package/cli/commands/spec-list.mjs +225 -0
  15. package/cli/commands/validate.mjs +12 -13
  16. package/cli/commands/verify-release.mjs +104 -0
  17. package/cli/cost-gate.mjs +323 -0
  18. package/cli/doctor.mjs +11 -8
  19. package/cli/provision.mjs +42 -16
  20. package/cli/worker-dispatcher.mjs +29 -0
  21. package/config/claude/agents/_shared/SKILLS.md +3 -1
  22. package/config/claude/agents/help-desk.md +1 -1
  23. package/config/claude/agents/principal-engineer.md +1 -1
  24. package/config/claude/agents/senior-engineer.md +1 -1
  25. package/config/claude/commands/tools.md +1 -1
  26. package/config/claude/commands/use-default.md +9 -8
  27. package/config/claude/commands/use-premium.md +12 -7
  28. package/config/claude/hooks/git-workflow-guard.mjs +14 -0
  29. package/config/claude/hooks/permission-request.mjs +176 -11
  30. package/config/claude/hooks/worker-suggest.mjs +42 -7
  31. package/config/claude/model-router.json +3 -3
  32. package/config/claude/settings.json +5 -49
  33. package/config/trigger-patterns.json +285 -85
  34. package/package.json +1 -1
  35. package/packages/sdk/dist/autonomy/evidence-bundle.d.ts +126 -0
  36. package/packages/sdk/dist/autonomy/evidence-bundle.js +100 -0
  37. package/packages/sdk/dist/autonomy/index.d.ts +12 -0
  38. package/packages/sdk/dist/autonomy/index.js +12 -0
  39. package/packages/sdk/dist/autonomy/objective-run.d.ts +107 -0
  40. package/packages/sdk/dist/autonomy/objective-run.js +94 -0
  41. package/packages/sdk/dist/autonomy/outcome-record.d.ts +62 -0
  42. package/packages/sdk/dist/autonomy/outcome-record.js +62 -0
  43. package/packages/sdk/dist/bench/auto-reduction.d.ts +91 -0
  44. package/packages/sdk/dist/bench/auto-reduction.js +130 -0
  45. package/packages/sdk/dist/bench/efficiency.d.ts +174 -0
  46. package/packages/sdk/dist/bench/efficiency.js +202 -0
  47. package/packages/sdk/dist/bench/index.d.ts +15 -0
  48. package/packages/sdk/dist/bench/index.js +13 -0
  49. package/packages/sdk/dist/index.d.ts +3 -0
  50. package/packages/sdk/dist/index.js +7 -0
  51. package/packages/sdk/dist/learning/behavior-capture.d.ts +105 -0
  52. package/packages/sdk/dist/learning/behavior-capture.js +195 -0
  53. package/packages/sdk/dist/learning/index.d.ts +1 -0
  54. package/packages/sdk/dist/learning/index.js +2 -0
  55. package/packages/sdk/dist/release/index.d.ts +20 -0
  56. package/packages/sdk/dist/release/index.js +20 -0
  57. package/packages/sdk/dist/release/known-good-releases.d.ts +101 -0
  58. package/packages/sdk/dist/release/known-good-releases.js +200 -0
  59. package/packages/sdk/dist/release/provenance.d.ts +82 -0
  60. package/packages/sdk/dist/release/provenance.js +62 -0
  61. package/packages/sdk/dist/release/sbom.d.ts +77 -0
  62. package/packages/sdk/dist/release/sbom.js +114 -0
  63. package/packages/sdk/dist/release/signature.d.ts +84 -0
  64. package/packages/sdk/dist/release/signature.js +139 -0
  65. package/packages/sdk/dist/router/agent-model-registry.js +23 -3
  66. package/packages/sdk/dist/router/outcome-learner.js +13 -9
  67. package/packages/sdk/dist/version.d.ts +1 -1
  68. package/packages/sdk/dist/version.js +1 -1
  69. package/packages/sdk/package.json +3 -2
  70. package/scripts/git-hooks/pre-push +8 -2
  71. package/cli/commands/9router-picker-proxy.mjs +0 -100
  72. package/cli/commands/picker-proxy.mjs +0 -18
  73. package/config/claude/commands/picker.md +0 -20
  74. package/config/skills/9router/SKILL.md +0 -82
  75. package/config/skills/9router-chat/SKILL.md +0 -73
  76. package/config/skills/9router-embeddings/SKILL.md +0 -69
  77. package/config/skills/9router-image/SKILL.md +0 -86
  78. package/config/skills/9router-stt/SKILL.md +0 -79
  79. package/config/skills/9router-tts/SKILL.md +0 -80
  80. package/config/skills/9router-web-fetch/SKILL.md +0 -99
  81. package/config/skills/9router-web-search/SKILL.md +0 -91
package/cli/bin.mjs CHANGED
@@ -109,6 +109,10 @@ function showHelp() {
109
109
  restore Restore BizarHarness from a backup
110
110
  validate Validate the Bizar install
111
111
  setup-provider Configure a provider in ~/.claude/settings.json (since v6.2.2 installer doesn't touch providers)
112
+ release-provenance Generate SBOM + provenance + minisig for a release (audit #83)
113
+ verify-release Verify a release artifact set against the pinned allowlist
114
+ spec-list List SDK schemas, policy docs, and mirror sync status (audit #84)
115
+ bench Efficiency benchmarks + auto-fan-out rule (audit #85)
112
116
  team Run the office-manager orchestration agent
113
117
  subagent Run a named agent in read-only plan mode
114
118
  run Run Claude Code once (optionally --bg)
@@ -117,7 +121,6 @@ function showHelp() {
117
121
  claim <subcommand> GitHub-style claim protocol over feature_list.json
118
122
  task <subcommand> Durable dependency/worktree/path task coordination
119
123
  control <subcommand> Machine-readable agents/tasks/sessions/messages API
120
- picker-proxy <start> Run the 9router picker proxy (default port 20129)
121
124
  workflow <subcommand> Session-bound autopilot workflow state
122
125
  hook <name> Run a portable Claude Code hook
123
126
  worktree-merge <branch> Merge a feature branch with archive tag (no work lost)
@@ -448,6 +451,74 @@ async function main() {
448
451
  break;
449
452
  }
450
453
 
454
+ case 'release-provenance': {
455
+ const mod = await importCommand('release-provenance');
456
+ if (!mod) {
457
+ console.error(chalk.red(` ✗ Could not load release-provenance command module`));
458
+ process.exit(EXIT_ERROR);
459
+ return;
460
+ }
461
+ dbg('loaded command module:', 'release-provenance');
462
+ const code = await mod.run(cmdArgs);
463
+ if (typeof code === 'number') process.exit(code);
464
+ break;
465
+ }
466
+
467
+ case 'verify-release': {
468
+ const mod = await importCommand('verify-release');
469
+ if (!mod) {
470
+ console.error(chalk.red(` ✗ Could not load verify-release command module`));
471
+ process.exit(EXIT_ERROR);
472
+ return;
473
+ }
474
+ dbg('loaded command module:', 'verify-release');
475
+ const code = await mod.run(cmdArgs);
476
+ if (typeof code === 'number') process.exit(code);
477
+ break;
478
+ }
479
+
480
+ case 'spec-list': {
481
+ const mod = await importCommand('spec-list');
482
+ if (!mod) {
483
+ console.error(chalk.red(` ✗ Could not load spec-list command module`));
484
+ process.exit(EXIT_ERROR);
485
+ return;
486
+ }
487
+ dbg('loaded command module:', 'spec-list');
488
+ const code = await mod.run(cmdArgs);
489
+ if (typeof code === 'number') process.exit(code);
490
+ break;
491
+ }
492
+
493
+ case 'bench': {
494
+ const mod = await importCommand('bench');
495
+ if (!mod) {
496
+ console.error(chalk.red(` ✗ Could not load bench command module`));
497
+ process.exit(EXIT_ERROR);
498
+ return;
499
+ }
500
+ dbg('loaded command module:', 'bench');
501
+ const code = await mod.run(cmdArgs);
502
+ if (typeof code === 'number') process.exit(code);
503
+ break;
504
+ }
505
+
506
+ case 'improve': {
507
+ const mod = await importCommand('improve');
508
+ if (!mod) {
509
+ console.error(chalk.red(` ✗ Could not load improve command module`));
510
+ process.exit(EXIT_ERROR);
511
+ return;
512
+ }
513
+ dbg('loaded command module:', 'improve');
514
+ const found = await mod.run(cmd, cmdArgs, isHelpRequest);
515
+ if (found === false) {
516
+ console.error(chalk.red(` ✗ Usage: bizar improve <subcommand> — run 'bizar improve --help'`));
517
+ process.exit(EXIT_USAGE);
518
+ }
519
+ break;
520
+ }
521
+
451
522
  case 'model': {
452
523
  // Deprecated alias. Routes to the original `model.mjs` so the
453
524
  // legacy JSON shape (`{ providers: { ... }, total: N }`) and table
@@ -500,16 +571,28 @@ async function main() {
500
571
  break;
501
572
  }
502
573
 
503
- case 'picker-proxy': {
504
- await import('./commands/picker-proxy.mjs');
505
- return;
506
- }
507
-
574
+
508
575
  case 'worktree-merge': {
509
576
  await import('./commands/worktree-merge.mjs');
510
577
  return;
511
578
  }
512
579
 
580
+ case 'explain-run': {
581
+ const mod = await importCommand('explain-run');
582
+ if (!mod) {
583
+ console.error(chalk.red(` ✗ Could not load explain-run command module`));
584
+ process.exit(EXIT_ERROR);
585
+ return;
586
+ }
587
+ dbg('loaded command module:', 'explain-run');
588
+ const found = await mod.run(cmd, cmdArgs, isHelpRequest);
589
+ if (found === false) {
590
+ console.error(chalk.red(` ✗ Usage: bizar explain-run <id> — run 'bizar explain-run --help'`));
591
+ process.exit(EXIT_USAGE);
592
+ }
593
+ break;
594
+ }
595
+
513
596
  default: {
514
597
  console.error(chalk.red(` ✗ Unknown command: ${cmd}`));
515
598
  showHelp();
@@ -0,0 +1,360 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cli/commands/bench.mjs
4
+ *
5
+ * `bizar bench` — audit #85 (P2 efficiency benchmarks) operator surface.
6
+ *
7
+ * The SDK module at `packages/sdk/src/bench/efficiency.ts` is pure
8
+ * (no I/O, no env reads); this CLI is the thin operator wrapper that
9
+ * supplies the standard task profiles + auto-fan-out report and emits
10
+ * the JSON / human-readable output.
11
+ *
12
+ * Subcommands:
13
+ *
14
+ * bizar bench default: run all benchmarks
15
+ * bizar bench single-vs-multi compare fanOut=1 vs fanOut=4
16
+ * bizar bench sequential-vs-parallel compare serial vs parallel DAG
17
+ * bizar bench reviewers compare 0/1/2 reviewer gates
18
+ * bizar bench worktree compare worktree overhead vs saved conflict time
19
+ * bizar bench recommend-fan-out apply auto-fan-out rule to a context
20
+ * bizar bench --format=json|human output format (default: human)
21
+ * bizar bench --seed=N deterministic seed (default: 42)
22
+ *
23
+ * Why this exists: the audit calls out six required comparisons. We
24
+ * ship five as built-in subcommands; the sixth (research depth) is
25
+ * operator-configurable via `--tasks=<file.json>` and is intentionally
26
+ * left to workflow owners to specialize. The auto-fan-out report is
27
+ * the audit's "automatically reduce fan-out when coordination
28
+ * overhead exceeds expected benefit" rule, surfaced as a runnable
29
+ * command rather than buried in a router.
30
+ */
31
+
32
+ import { readFileSync } from 'node:fs';
33
+ import {
34
+ EFFICIENCY_BENCH_SCHEMA_VERSION,
35
+ AUTO_REDUCTION_SCHEMA_VERSION,
36
+ runBench,
37
+ compareConfigurations,
38
+ recommendFanOut,
39
+ } from '../../packages/sdk/dist/bench/index.js';
40
+
41
+ const REPO_ROOT = process.cwd();
42
+
43
+ /**
44
+ * Default synthetic workload: a 4-task chain where each task is
45
+ * roughly independent. Matches a typical "implement a feature" pass
46
+ * (research → design → implement → verify).
47
+ */
48
+ function defaultTasks() {
49
+ return [
50
+ { id: 'research', workMs: 4_000, costUsd: 12_000, successProb: 0.95, quality: 0.80 },
51
+ { id: 'design', workMs: 3_000, costUsd: 10_000, successProb: 0.90, quality: 0.85 },
52
+ { id: 'implement',workMs: 8_000, costUsd: 24_000, successProb: 0.85, quality: 0.75 },
53
+ { id: 'verify', workMs: 3_000, costUsd: 8_000, successProb: 0.92, quality: 0.88 },
54
+ ];
55
+ }
56
+
57
+ function loadTasks(args) {
58
+ const tasksFlag = args.find((a) => a.startsWith('--tasks='));
59
+ if (tasksFlag) {
60
+ const path = tasksFlag.slice('--tasks='.length);
61
+ const abs = path.startsWith('/') ? path : `${REPO_ROOT}/${path}`;
62
+ const raw = JSON.parse(readFileSync(abs, 'utf8'));
63
+ if (!Array.isArray(raw)) {
64
+ throw new TypeError('--tasks=<file.json> must contain a JSON array');
65
+ }
66
+ return raw;
67
+ }
68
+ return defaultTasks();
69
+ }
70
+
71
+ function seedOf(args) {
72
+ const sFlag = args.find((a) => a.startsWith('--seed='));
73
+ return sFlag ? Number(sFlag.slice('--seed='.length)) : 42;
74
+ }
75
+
76
+ function formatOf(args) {
77
+ const fFlag = args.find((a) => a.startsWith('--format='));
78
+ return fFlag ? fFlag.slice('--format='.length) : 'human';
79
+ }
80
+
81
+ /** Configurations for the single-vs-multi comparison. */
82
+ function configsSingleVsMulti() {
83
+ return [
84
+ { label: 'single-agent', fanOut: 1, reviewerCount: 1, parallel: false, coordinationOverheadRatio: 0.0 },
85
+ { label: 'multi-agent-par', fanOut: 4, reviewerCount: 1, parallel: true, coordinationOverheadRatio: 0.15 },
86
+ ];
87
+ }
88
+
89
+ function configsSequentialVsParallel() {
90
+ return [
91
+ { label: 'sequential', fanOut: 1, reviewerCount: 1, parallel: false, coordinationOverheadRatio: 0.0 },
92
+ { label: 'parallel-dag', fanOut: 4, reviewerCount: 1, parallel: true, coordinationOverheadRatio: 0.10 },
93
+ ];
94
+ }
95
+
96
+ function configsReviewers() {
97
+ return [
98
+ { label: 'no-reviewers', fanOut: 1, reviewerCount: 0, parallel: false, coordinationOverheadRatio: 0.0 },
99
+ { label: '1-reviewer', fanOut: 1, reviewerCount: 1, parallel: false, coordinationOverheadRatio: 0.0 },
100
+ { label: '2-reviewers', fanOut: 1, reviewerCount: 2, parallel: false, coordinationOverheadRatio: 0.0 },
101
+ ];
102
+ }
103
+
104
+ function configsWorktree() {
105
+ // 4 workers with and without worktree overhead.
106
+ return [
107
+ { label: 'no-worktree', fanOut: 4, reviewerCount: 1, parallel: true, coordinationOverheadRatio: 0.10 },
108
+ { label: 'with-worktree', fanOut: 4, reviewerCount: 1, parallel: true, coordinationOverheadRatio: 0.35 },
109
+ ];
110
+ }
111
+
112
+ function runComparison(tasks, configs, seed) {
113
+ const [a, b] = configs;
114
+ return compareConfigurations(tasks, a, b, seed);
115
+ }
116
+
117
+ function benchSingleVsMulti(tasks, seed) {
118
+ return runComparison(tasks, configsSingleVsMulti(), seed);
119
+ }
120
+
121
+ function benchSequentialVsParallel(tasks, seed) {
122
+ return runComparison(tasks, configsSequentialVsParallel(), seed);
123
+ }
124
+
125
+ function benchReviewers(tasks, seed) {
126
+ const configs = configsReviewers();
127
+ return configs.map((c) => runBench(tasks, c, seed));
128
+ }
129
+
130
+ function benchWorktree(tasks, seed) {
131
+ return runComparison(tasks, configsWorktree(), seed);
132
+ }
133
+
134
+ /**
135
+ * Render a single BenchResult as a fixed-width row.
136
+ */
137
+ function formatRow(r) {
138
+ const cost = Number.isFinite(r.costPerVerifiedUsd)
139
+ ? (r.costPerVerifiedUsd / 1_000_000).toFixed(4) + ' USD'
140
+ : '∞';
141
+ const wall = Number.isFinite(r.wallClockPerVerifiedMs)
142
+ ? r.wallClockPerVerifiedMs.toFixed(0) + ' ms'
143
+ : '∞';
144
+ return [
145
+ r.configLabel.padEnd(22),
146
+ `fanOut=${String(r.fanOut).padEnd(2)}`,
147
+ `reviewers=${r.reviewerCount}`,
148
+ `verified=${String(r.verifiedOutcomes).padEnd(2)}/${r.totalAttempts}`,
149
+ `cost/v=${cost.padStart(10)}`,
150
+ `wall/v=${wall.padStart(10)}`,
151
+ ].join(' ');
152
+ }
153
+
154
+ function renderHumanSingleVsMulti(comparison) {
155
+ const out = [];
156
+ out.push(' single-agent vs multi-agent (audit #85)');
157
+ out.push('');
158
+ out.push(' ' + formatRow(comparison.a));
159
+ out.push(' ' + formatRow(comparison.b));
160
+ out.push('');
161
+ out.push(
162
+ ` cost ratio (a/b): ${comparison.costRatioAOverB.toFixed(2)} wall ratio (a/b): ${comparison.wallClockRatioAOverB.toFixed(2)}`,
163
+ );
164
+ out.push(
165
+ ` winner by cost: ${comparison.costWinner} winner by wall-clock: ${comparison.wallClockWinner}`,
166
+ );
167
+ return out.join('\n');
168
+ }
169
+
170
+ function renderHumanSequentialVsParallel(comparison) {
171
+ const out = [];
172
+ out.push(' sequential vs parallel DAG (audit #85)');
173
+ out.push('');
174
+ out.push(' ' + formatRow(comparison.a));
175
+ out.push(' ' + formatRow(comparison.b));
176
+ out.push('');
177
+ out.push(
178
+ ` wall-clock speedup (a/b): ${comparison.wallClockRatioAOverB.toFixed(2)} (lower = sequential is faster)`,
179
+ );
180
+ return out.join('\n');
181
+ }
182
+
183
+ function renderHumanReviewers(results) {
184
+ const out = [];
185
+ out.push(' reviewer count vs verified outcomes (audit #85)');
186
+ out.push('');
187
+ for (const r of results) {
188
+ out.push(' ' + formatRow(r));
189
+ }
190
+ out.push('');
191
+ out.push(' expectation: 0 reviewers = cheapest, highest defect rate;');
192
+ out.push(' 2 reviewers = lowest defect rate, ~2× reviewer cost.');
193
+ return out.join('\n');
194
+ }
195
+
196
+ function renderHumanWorktree(comparison) {
197
+ const out = [];
198
+ out.push(' worktree overhead vs saved conflict time (audit #85)');
199
+ out.push('');
200
+ out.push(' ' + formatRow(comparison.a));
201
+ out.push(' ' + formatRow(comparison.b));
202
+ out.push('');
203
+ out.push(
204
+ ` observed overhead ratios: a=${comparison.a.observedOverheadRatio.toFixed(2)} b=${comparison.b.observedOverheadRatio.toFixed(2)}`,
205
+ );
206
+ out.push(
207
+ ` verdict: ${comparison.a.totalWallClockMs <= comparison.b.totalWallClockMs ? 'no-worktree' : 'with-worktree'} wins on wall-clock`,
208
+ );
209
+ return out.join('\n');
210
+ }
211
+
212
+ function renderHumanAutoReduction(decision, ctx) {
213
+ const out = [];
214
+ out.push(' recommend-fan-out (auto-reduction rule, audit #85)');
215
+ out.push('');
216
+ out.push(` context: fanOut=${ctx.currentFanOut} overheadRatio=${ctx.historicalCoordinationOverheadRatio} expectedBenefitRatio=${ctx.expectedBenefitRatio} defectEscapeRate=${ctx.historicalDefectEscapeRate}`);
217
+ out.push(` recommended fan-out: ${decision.recommendedFanOut}`);
218
+ out.push(` reason: ${decision.reason}`);
219
+ out.push(` overhead-vs-benefit: ${decision.overheadVsBenefitGap.toFixed(3)}`);
220
+ out.push(` reduced: ${decision.reduced}`);
221
+ out.push('');
222
+ out.push(' rule:');
223
+ out.push(' defectEscapeRate > 0.20 → verifier-cannot-certify (fan-out unchanged; widen reviewers)');
224
+ out.push(' overheadRatio >= benefit → reduce by one step (single-worker-fan-out at floor)');
225
+ out.push(' otherwise → keep-current');
226
+ return out.join('\n');
227
+ }
228
+
229
+ function parseFlags(args) {
230
+ const flags = {};
231
+ for (let i = 0; i < args.length; i++) {
232
+ const arg = args[i];
233
+ if (arg.startsWith('--')) {
234
+ const key = arg.slice(2);
235
+ const eq = key.indexOf('=');
236
+ if (eq >= 0) {
237
+ flags[key.slice(0, eq)] = key.slice(eq + 1);
238
+ } else {
239
+ const next = args[i + 1];
240
+ if (!next || next.startsWith('--')) flags[key] = true;
241
+ else { flags[key] = next; i++; }
242
+ }
243
+ }
244
+ }
245
+ return flags;
246
+ }
247
+
248
+ function parseAutoReductionFlags(args) {
249
+ // bizar bench recommend-fan-out --fan-out=N --overhead=R --benefit=R --escape=R
250
+ const flags = parseFlags(args);
251
+ const fanOut = Number(flags['fan-out'] ?? flags.fanOut ?? 4);
252
+ const overhead = Number(flags.overhead ?? 0.5);
253
+ const benefit = Number(flags.benefit ?? 0.6);
254
+ const escape = Number(flags.escape ?? 0.05);
255
+ return {
256
+ currentFanOut: fanOut,
257
+ historicalCoordinationOverheadRatio: overhead,
258
+ expectedBenefitRatio: benefit,
259
+ historicalDefectEscapeRate: escape,
260
+ };
261
+ }
262
+
263
+ export const USAGE = `
264
+ bizar bench — audit #85 efficiency benchmarks + auto-fan-out rule
265
+
266
+ Usage:
267
+ bizar bench [single-vs-multi | sequential-vs-parallel | reviewers | worktree]
268
+ [--format=json|human] [--seed=N] [--tasks=<file.json>]
269
+ bizar bench recommend-fan-out --fan-out=N --overhead=R --benefit=R --escape=R
270
+ [--format=json|human]
271
+
272
+ Subcommands (default: run all four):
273
+ single-vs-multi fanOut=1 sequential vs fanOut=4 parallel
274
+ sequential-vs-parallel serial 4-task chain vs parallel 4-task DAG
275
+ reviewers 0/1/2 reviewer gates on the same task set
276
+ worktree coordination overhead 0.10 vs 0.35
277
+
278
+ recommend-fan-out:
279
+ bizar bench recommend-fan-out --fan-out=4 --overhead=0.5 --benefit=0.6 --escape=0.05
280
+ Applies the audit's "automatically reduce fan-out when coordination
281
+ overhead exceeds expected benefit" rule.
282
+
283
+ Schema versions:
284
+ bench/efficiency.ts ${EFFICIENCY_BENCH_SCHEMA_VERSION}
285
+ bench/auto-reduction.ts ${AUTO_REDUCTION_SCHEMA_VERSION}
286
+ `;
287
+
288
+ export async function run(subargs) {
289
+ if (subargs.includes('--help') || subargs.includes('-h')) {
290
+ console.log(USAGE);
291
+ return 0;
292
+ }
293
+
294
+ const subcommand = subargs.find((a) => !a.startsWith('--'));
295
+
296
+ if (subcommand === 'recommend-fan-out') {
297
+ const ctx = parseAutoReductionFlags(subargs);
298
+ const decision = recommendFanOut(ctx);
299
+ if (formatOf(subargs) === 'json') {
300
+ console.log(JSON.stringify({ context: ctx, decision, schemaVersion: AUTO_REDUCTION_SCHEMA_VERSION }, null, 2));
301
+ } else {
302
+ console.log(renderHumanAutoReduction(decision, ctx));
303
+ }
304
+ return 0;
305
+ }
306
+
307
+ const tasks = loadTasks(subargs);
308
+ const seed = seedOf(subargs);
309
+ const format = formatOf(subargs);
310
+ const runOne = subcommand === undefined;
311
+ const want = (name) => runOne || subcommand === name;
312
+
313
+ const out = { schemaVersion: EFFICIENCY_BENCH_SCHEMA_VERSION, generatedAt: new Date().toISOString() };
314
+
315
+ if (want('single-vs-multi')) {
316
+ out.singleVsMulti = benchSingleVsMulti(tasks, seed);
317
+ }
318
+ if (want('sequential-vs-parallel')) {
319
+ out.sequentialVsParallel = benchSequentialVsParallel(tasks, seed);
320
+ }
321
+ if (want('reviewers')) {
322
+ out.reviewers = benchReviewers(tasks, seed);
323
+ }
324
+ if (want('worktree')) {
325
+ out.worktree = benchWorktree(tasks, seed);
326
+ }
327
+
328
+ if (Object.keys(out).length === 2) {
329
+ console.log(USAGE);
330
+ return 1;
331
+ }
332
+
333
+ if (format === 'json') {
334
+ console.log(JSON.stringify(out, null, 2));
335
+ } else {
336
+ console.log(`bizar bench — audit #85 (generated ${out.generatedAt}, seed=${seed})`);
337
+ console.log('');
338
+ if (out.singleVsMulti) {
339
+ console.log(renderHumanSingleVsMulti(out.singleVsMulti));
340
+ console.log('');
341
+ }
342
+ if (out.sequentialVsParallel) {
343
+ console.log(renderHumanSequentialVsParallel(out.sequentialVsParallel));
344
+ console.log('');
345
+ }
346
+ if (out.reviewers) {
347
+ console.log(renderHumanReviewers(out.reviewers));
348
+ console.log('');
349
+ }
350
+ if (out.worktree) {
351
+ console.log(renderHumanWorktree(out.worktree));
352
+ console.log('');
353
+ }
354
+ }
355
+ return 0;
356
+ }
357
+
358
+ if (import.meta.url === `file://${process.argv[1]}`) {
359
+ run(process.argv.slice(2)).then((code) => process.exit(code));
360
+ }