@geenius/release-toolkit 0.10.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.
@@ -0,0 +1,1401 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * Public report shapes. Stable across versions — schema changes require a minor
5
+ * bump and an explicit CHANGELOG entry. Downstream consumers (CI integrations,
6
+ * coverage aggregators, gauntlet runners) parse these reports directly.
7
+ */
8
+ type StepStatus = "passed" | "failed" | "skipped" | "missing" | "unauthenticated";
9
+ type CommandStatus = "passed" | "failed" | "skipped";
10
+ interface StepReport {
11
+ /** Human-readable step name, e.g. `"pnpm audit"`, `"osv-scanner"`, `"smoke @geenius/ai-magic/react"`. */
12
+ name: string;
13
+ status: StepStatus;
14
+ /** Short reason for non-passed states. */
15
+ reason?: string;
16
+ durationMs: number;
17
+ /** Last 4 KB of combined stdout/stderr; useful for triage without re-running. */
18
+ output?: string;
19
+ }
20
+ interface CommandReport {
21
+ /** Canonical command name (e.g. `"supply-chain"`, `"license"`). */
22
+ command: string;
23
+ status: CommandStatus;
24
+ /** ISO 8601 timestamp when the command started. */
25
+ startedAt: string;
26
+ durationMs: number;
27
+ steps: StepReport[];
28
+ /** Free-form metadata: package name, fixture id, version, etc. */
29
+ meta?: Record<string, unknown>;
30
+ }
31
+ /** Per-scanner runtime state. Distinct from `StepStatus` because a `missing`
32
+ * scanner is data, not failure, and the same `missing` value can map to
33
+ * different downstream behavior (`passed`/`skipped`/`failed`) depending on
34
+ * the scanner's `required` configuration.
35
+ */
36
+ type ScannerState = {
37
+ kind: "passed";
38
+ output?: string;
39
+ } | {
40
+ kind: "failed";
41
+ reason: string;
42
+ output?: string;
43
+ } | {
44
+ kind: "missing";
45
+ reason: string;
46
+ } | {
47
+ kind: "unauthenticated";
48
+ reason: string;
49
+ };
50
+
51
+ /**
52
+ * `geenius-release a11y-report` — aggregate axe-core results that the package's
53
+ * a11y test run produced. Replaces 28 copies of `a11y-report.mjs`.
54
+ *
55
+ * Looks for a single JSON file at `.eval/a11y/results.json` (or the path
56
+ * passed via `--results`) containing the axe output. Reports the count of
57
+ * violations by severity. Fails when any violation at or above
58
+ * `failThreshold` exists (default: `serious`).
59
+ */
60
+
61
+ type A11ySeverity = "minor" | "moderate" | "serious" | "critical";
62
+ interface RunA11yReportOptions {
63
+ cwd?: string;
64
+ /** Path to the axe results JSON. Default: `.eval/a11y/results.json`. */
65
+ resultsPath?: string;
66
+ /** Lowest severity that fails the report. Default: `serious`. */
67
+ failThreshold?: A11ySeverity;
68
+ /** Whether absent results is `failed` or `skipped`. */
69
+ optional?: boolean;
70
+ quiet?: boolean;
71
+ }
72
+ declare function runA11yReport(opts?: RunA11yReportOptions): Promise<CommandReport>;
73
+
74
+ /**
75
+ * `geenius-release attw` — run @arethetypeswrong/cli against the packed tarball.
76
+ * Replaces ~13 scripts across 3 filename variations (`run-attw.mjs`,
77
+ * `attw-packed.mjs`, `attw-check.mjs`).
78
+ */
79
+
80
+ interface RunAttwOptions {
81
+ cwd?: string;
82
+ /** Allow attw to be missing without failing. */
83
+ optional?: boolean;
84
+ /** Comma list of attw `--ignore-rules` (e.g. `cjs-resolves-to-esm`). */
85
+ ignoreRules?: readonly string[];
86
+ /** Reuse a stable directory (relative to packageRoot) for the tarball
87
+ * instead of `mkdtempSync(os.tmpdir())`. Useful when concurrent pnpm
88
+ * installs in the global cache thrash mkdtemp creations. Default:
89
+ * undefined (use os.tmpdir). Common value: `.eval/attw-pack`. */
90
+ safePackDir?: string;
91
+ quiet?: boolean;
92
+ }
93
+ declare function runAttw(opts?: RunAttwOptions): Promise<CommandReport>;
94
+
95
+ /**
96
+ * `geenius-release bundle-budgets` — variants.json-native gzip bundle budgets.
97
+ *
98
+ * Replaces `scripts/check-bundle-budgets.mjs` (currently 1 copy in perf, but
99
+ * 8 packages declare `bundleBudget` in their variants.json: perf, agent,
100
+ * ai-magic, devtools, errors, onboarding, ui, tools-legacy — so the pattern
101
+ * is genuinely shared).
102
+ *
103
+ * For every implemented variant declaring `bundleBudget: "<n><unit>"`:
104
+ * 1. Gzip-sum every declared runtime asset (default: index.js + index.css)
105
+ * in <packageDir>/dist.
106
+ * 2. Compare against the parsed budget (b / kb / mb units).
107
+ * 3. Fail with a per-variant overshoot list on any violation.
108
+ *
109
+ * Distinct from `size-check` (which uses the external `size-limit` tool with
110
+ * its own config) and from `size-limit-config` (which generates a size-limit
111
+ * config from variants.json). This command is the lightweight, zero-extra-
112
+ * dependency path that just reads the manifest and the dist tree.
113
+ */
114
+ interface RunBundleBudgetsOptions {
115
+ cwd?: string;
116
+ /** Runtime asset basenames to gzip-sum per variant (default: index.js, index.css). */
117
+ assets?: string[];
118
+ /** Only include variants flagged `implemented: true` (default: true). */
119
+ implementedOnly?: boolean;
120
+ /** Skip silently when no variant declares a budget. */
121
+ optional?: boolean;
122
+ }
123
+ interface BundleBudgetsResult {
124
+ status: "passed" | "failed" | "skipped";
125
+ exitCode: number;
126
+ rows: BudgetRow[];
127
+ failures: string[];
128
+ }
129
+ interface BudgetRow {
130
+ name: string;
131
+ packageDir: string;
132
+ budgetBytes: number;
133
+ gzipBytes: number;
134
+ uncompressedBytes: number;
135
+ assets: string[];
136
+ }
137
+ declare function runBundleBudgets(opts?: RunBundleBudgetsOptions): Promise<BundleBudgetsResult>;
138
+
139
+ /**
140
+ * `geenius-release convex-build` — build a Convex sub-package.
141
+ *
142
+ * Replaces the per-package `build: "node ../../scripts/geenius-convex-codegen.mjs --src src && tsup"`
143
+ * pattern (repeated across the 16 Convex-bearing packages).
144
+ *
145
+ * Equivalent to:
146
+ * geenius-release convex-codegen --src <src> # default: src/
147
+ * tsup
148
+ *
149
+ * Flags:
150
+ * --src <dir> Convex source dir (default: src)
151
+ * --no-codegen Skip codegen, just run tsup
152
+ * --no-build Run codegen only
153
+ * --clean Clean _generated/ instead of building
154
+ */
155
+ interface RunConvexBuildOptions {
156
+ cwd?: string;
157
+ src?: string;
158
+ noCodegen?: boolean;
159
+ noBuild?: boolean;
160
+ clean?: boolean;
161
+ /** Builder to invoke (default: "tsup"). */
162
+ builder?: "tsup" | "tsc";
163
+ /** Extra args forwarded to the builder. */
164
+ passthrough?: string[];
165
+ }
166
+ interface ConvexBuildResult {
167
+ status: "passed" | "failed";
168
+ exitCode: number;
169
+ steps: {
170
+ name: string;
171
+ exitCode: number;
172
+ }[];
173
+ }
174
+ declare function runConvexBuild(opts?: RunConvexBuildOptions): Promise<ConvexBuildResult>;
175
+
176
+ /**
177
+ * `geenius-release convex-codegen` — generate `_generated/` shims for Convex
178
+ * variants.
179
+ *
180
+ * Promotes the standalone `geenius-convex-codegen` script (vendored in
181
+ * geenius-payments and shipped as a bin from geenius-db's convex subpackage)
182
+ * into a first-class toolkit command. All Convex-bearing packages can drop
183
+ * their per-package copy and call this instead.
184
+ *
185
+ * Behaviour:
186
+ * - Discovers the convex source dir by trying (in order):
187
+ * opts.src → packages/convex/src → src → cwd
188
+ * - Generates: server.js, server.d.ts, dataModel.d.ts, api.js, api.d.ts
189
+ * - `--check` mode: verify files are up to date; exit 1 if not.
190
+ * - `--clean` mode: delete `_generated/` and exit.
191
+ */
192
+ interface RunConvexCodegenOptions {
193
+ cwd?: string;
194
+ /** Override source directory. */
195
+ src?: string;
196
+ /** Check-only — exit 1 if any file would be written/changed. */
197
+ check?: boolean;
198
+ /** Delete the _generated/ directory. */
199
+ clean?: boolean;
200
+ }
201
+ interface ConvexCodegenResult {
202
+ status: "passed" | "failed" | "skipped";
203
+ exitCode: number;
204
+ srcDir: string;
205
+ files: {
206
+ name: string;
207
+ status: "new" | "changed" | "unchanged";
208
+ }[];
209
+ modules: string[];
210
+ warnings: string[];
211
+ }
212
+ declare function runConvexCodegen(opts?: RunConvexCodegenOptions): Promise<ConvexCodegenResult>;
213
+
214
+ /**
215
+ * `geenius-release coverage` — canonical vitest --coverage runner.
216
+ *
217
+ * Collapses run-coverage.mjs (5) and the various ad-hoc vitest invocations.
218
+ *
219
+ * Behaviour:
220
+ * 1. Clean root + per-variant coverage/ directories.
221
+ * 2. Run `vitest run --coverage` at the root, excluding tests from any
222
+ * variant packages flagged as `separateCoverage: true` (or matching
223
+ * `--separate-coverage <framework>`).
224
+ * 3. For each separate-coverage package, run vitest inside that package
225
+ * directory so its own coverage report is emitted.
226
+ *
227
+ * Emits the same JSON shape downstream `coverage-report` expects.
228
+ */
229
+ interface RunCoverageOptions {
230
+ cwd?: string;
231
+ /** Run separate vitest passes for variants whose framework matches. */
232
+ separateFrameworks?: string[];
233
+ /** Explicit list of packageDirs to run separately (overrides framework match). */
234
+ separatePackageDirs?: string[];
235
+ /** Skip the cleanup phase. */
236
+ noClean?: boolean;
237
+ /** Strict mode flag forwarded to tests via GEENIUS_COVERAGE_STRICT. */
238
+ strict?: boolean;
239
+ /** Extra args appended to every vitest call. */
240
+ passthrough?: string[];
241
+ }
242
+ interface CoverageResult {
243
+ status: "passed" | "failed" | "skipped";
244
+ exitCode: number;
245
+ passes: {
246
+ label: string;
247
+ cwd: string;
248
+ exitCode: number;
249
+ }[];
250
+ }
251
+ declare function runCoverage(opts?: RunCoverageOptions): Promise<CoverageResult>;
252
+
253
+ /**
254
+ * `geenius-release coverage-report` — aggregate the coverage summary that
255
+ * vitest (or any tool writing coverage-summary.json / coverage-final.json)
256
+ * produced. Replaces 36 copies of `coverage-report.mjs`.
257
+ *
258
+ * Reads `coverage/coverage-summary.json` (default v8/istanbul output path).
259
+ * Optional thresholds: minimum % lines / branches / functions / statements.
260
+ */
261
+
262
+ interface CoverageThresholds {
263
+ lines?: number;
264
+ branches?: number;
265
+ functions?: number;
266
+ statements?: number;
267
+ }
268
+ interface RunCoverageReportOptions {
269
+ cwd?: string;
270
+ /** Path to coverage-summary.json. Default: `coverage/coverage-summary.json`. */
271
+ summaryPath?: string;
272
+ /** Minimum percentages. Default: pull from `coverage-thresholds.json` if present
273
+ * (legacy flat shape). When `thresholdFile` is set, the per-subpackage shape
274
+ * there takes precedence. */
275
+ thresholds?: CoverageThresholds;
276
+ /** Path to a richer per-subpackage threshold JSON (shape:
277
+ * `{ subpackages: { <name>: { thresholds: { lines, statements, branches, functions }, required?, kind? } } }`).
278
+ * When set, the toolkit emits per-subpackage results in addition to the
279
+ * totals row. Subpackages keyed by name look for `coverage/coverage-summary.json`
280
+ * files at `packages/<name>/coverage/`, `<name>/coverage/`, or matching prefix
281
+ * inside the root summary. */
282
+ thresholdFile?: string;
283
+ /** Write a Markdown report to this path. */
284
+ output?: string;
285
+ /** Write a structured JSON report to this path. */
286
+ json?: string;
287
+ /** Treat any subpackage below threshold as a failure (default: true when
288
+ * `thresholdFile` is set, false otherwise — matches legacy --fail-on-gaps
289
+ * flag in per-package scripts). */
290
+ failOnGaps?: boolean;
291
+ /** Whether absent coverage is `failed` (default) or `skipped`. */
292
+ optional?: boolean;
293
+ quiet?: boolean;
294
+ }
295
+ declare function runCoverageReport(opts?: RunCoverageReportOptions): Promise<CommandReport>;
296
+
297
+ /**
298
+ * `geenius-release db-migrations` — run migration tests across db-provider
299
+ * variants.
300
+ *
301
+ * Collapses db-migrations-check.mjs (4 packages). For every variant with
302
+ * kind `db-provider` and `tests.migrations: true`, runs:
303
+ * pnpm --filter ./<packageDir> test -- -t migration
304
+ *
305
+ * Fails fast on the first non-zero status by default.
306
+ */
307
+ interface RunDbMigrationsOptions {
308
+ cwd?: string;
309
+ /** Only run providers whose name matches one of these. */
310
+ only?: string[];
311
+ /** Don't bail on first failure. */
312
+ continueOnFailure?: boolean;
313
+ /** Test-name pattern passed to vitest (default: "migration"). */
314
+ pattern?: string;
315
+ }
316
+ interface DbMigrationsResult {
317
+ status: "passed" | "failed" | "skipped";
318
+ exitCode: number;
319
+ ran: {
320
+ name: string;
321
+ packageDir: string;
322
+ exitCode: number;
323
+ }[];
324
+ }
325
+ declare function runDbMigrations(opts?: RunDbMigrationsOptions): Promise<DbMigrationsResult>;
326
+
327
+ /**
328
+ * `geenius-release diff-coverage` — changed-line coverage diff against a base
329
+ * git ref. Replaces 22 copies of `diff-coverage.mjs`.
330
+ *
331
+ * Computes which source lines were added or modified between `--base` (default
332
+ * `origin/main`) and `HEAD`, then walks the latest `coverage-final.json` to
333
+ * check whether every such line was hit. Fails if the changed-line coverage
334
+ * percentage falls below `--min`.
335
+ */
336
+
337
+ interface RunDiffCoverageOptions {
338
+ cwd?: string;
339
+ /** Git ref to diff against. Default: `origin/main`. */
340
+ base?: string;
341
+ /** Path to vitest's coverage-final.json. Default: `coverage/coverage-final.json`. */
342
+ coveragePath?: string;
343
+ /** Minimum changed-line coverage % required to pass. Default: 80. */
344
+ min?: number;
345
+ /** When `process.env.CI === "true"`, use this threshold instead of `min`. */
346
+ minCi?: number;
347
+ /** When `process.env.CI` is unset/falsy, use this threshold. Overrides `min`
348
+ * for local runs. Common pattern: 0 locally + strict in CI. */
349
+ minLocal?: number;
350
+ /** Skip if coverage hasn't been run. Default: false. */
351
+ optional?: boolean;
352
+ quiet?: boolean;
353
+ }
354
+ declare function runDiffCoverage(opts?: RunDiffCoverageOptions): Promise<CommandReport>;
355
+
356
+ /**
357
+ * `geenius-release e2e` — canonical Playwright runner.
358
+ *
359
+ * Collapses e2e-runner.mjs (5) + playwright-projects.mjs (2).
360
+ *
361
+ * Responsibilities:
362
+ * 1. Reserve ephemeral ports per UI harness variant and inject them as
363
+ * `<PACKAGE>_E2E_<VARIANT>_PORT` env vars (mirroring the existing
364
+ * per-package e2e-runner pattern).
365
+ * 2. Derive `--project=<variantName>-<browser>` filters from variants.json
366
+ * when callers pass `--projects` or `--all-browsers`.
367
+ * 3. Forward all other args to `pnpm exec playwright test`.
368
+ */
369
+ interface RunE2EOptions {
370
+ cwd?: string;
371
+ /** Emit `--project=<variant>-<browser>` projects for every e2e variant. */
372
+ projects?: boolean;
373
+ /** When true with projects, include every browser declared on each variant. */
374
+ allBrowsers?: boolean;
375
+ /** Specific browser to use (default: chromium) when --projects. */
376
+ browser?: string;
377
+ /** Env prefix for port vars. Default: derived from package.json name. */
378
+ envPrefix?: string;
379
+ /** Extra args forwarded to `playwright test`. */
380
+ passthrough?: string[];
381
+ /** Print resolved env + command and exit. */
382
+ print?: boolean;
383
+ }
384
+ interface E2EResult {
385
+ status: "passed" | "failed" | "skipped";
386
+ exitCode: number;
387
+ ports: Record<string, string>;
388
+ projects: string[];
389
+ }
390
+ declare function runE2E(opts?: RunE2EOptions): Promise<E2EResult>;
391
+
392
+ /**
393
+ * Configuration: schema, defaults, loader.
394
+ *
395
+ * The single Zod schema below is the source of truth for `release-toolkit.config.json`.
396
+ * Defaults are applied per-field so that an absent config file is equivalent to
397
+ * an empty `{}` — every consumer gets sensible behaviour out of the box.
398
+ */
399
+
400
+ declare const ConfigSchema: z.ZodObject<{
401
+ $schema: z.ZodOptional<z.ZodString>;
402
+ variants: z.ZodDefault<z.ZodObject<{
403
+ include: z.ZodOptional<z.ZodArray<z.ZodString>>;
404
+ exclude: z.ZodOptional<z.ZodArray<z.ZodString>>;
405
+ }, z.core.$strict>>;
406
+ supplyChain: z.ZodDefault<z.ZodObject<{
407
+ scanners: z.ZodDefault<z.ZodObject<{
408
+ pnpmAudit: z.ZodDefault<z.ZodObject<{
409
+ required: z.ZodDefault<z.ZodBoolean>;
410
+ auditLevel: z.ZodDefault<z.ZodEnum<{
411
+ low: "low";
412
+ moderate: "moderate";
413
+ high: "high";
414
+ critical: "critical";
415
+ }>>;
416
+ scope: z.ZodDefault<z.ZodEnum<{
417
+ prod: "prod";
418
+ all: "all";
419
+ }>>;
420
+ skipIfMissing: z.ZodOptional<z.ZodEnum<{
421
+ silent: "silent";
422
+ info: "info";
423
+ warn: "warn";
424
+ }>>;
425
+ skipIfUnauthenticated: z.ZodOptional<z.ZodEnum<{
426
+ silent: "silent";
427
+ info: "info";
428
+ warn: "warn";
429
+ }>>;
430
+ }, z.core.$strict>>;
431
+ osvScanner: z.ZodDefault<z.ZodObject<{
432
+ required: z.ZodDefault<z.ZodBoolean>;
433
+ skipIfMissing: z.ZodDefault<z.ZodEnum<{
434
+ silent: "silent";
435
+ info: "info";
436
+ warn: "warn";
437
+ }>>;
438
+ skipIfUnauthenticated: z.ZodOptional<z.ZodEnum<{
439
+ silent: "silent";
440
+ info: "info";
441
+ warn: "warn";
442
+ }>>;
443
+ }, z.core.$strict>>;
444
+ socket: z.ZodDefault<z.ZodObject<{
445
+ required: z.ZodDefault<z.ZodBoolean>;
446
+ skipIfMissing: z.ZodDefault<z.ZodEnum<{
447
+ silent: "silent";
448
+ info: "info";
449
+ warn: "warn";
450
+ }>>;
451
+ skipIfUnauthenticated: z.ZodDefault<z.ZodEnum<{
452
+ silent: "silent";
453
+ info: "info";
454
+ warn: "warn";
455
+ }>>;
456
+ }, z.core.$strict>>;
457
+ license: z.ZodDefault<z.ZodObject<{
458
+ required: z.ZodDefault<z.ZodBoolean>;
459
+ skipIfMissing: z.ZodOptional<z.ZodEnum<{
460
+ silent: "silent";
461
+ info: "info";
462
+ warn: "warn";
463
+ }>>;
464
+ skipIfUnauthenticated: z.ZodOptional<z.ZodEnum<{
465
+ silent: "silent";
466
+ info: "info";
467
+ warn: "warn";
468
+ }>>;
469
+ }, z.core.$strict>>;
470
+ }, z.core.$strict>>;
471
+ }, z.core.$strict>>;
472
+ license: z.ZodDefault<z.ZodObject<{
473
+ scope: z.ZodDefault<z.ZodEnum<{
474
+ prod: "prod";
475
+ all: "all";
476
+ }>>;
477
+ forbidden: z.ZodDefault<z.ZodArray<z.ZodString>>;
478
+ allowlist: z.ZodDefault<z.ZodArray<z.ZodString>>;
479
+ unknownPolicy: z.ZodDefault<z.ZodEnum<{
480
+ warn: "warn";
481
+ pass: "pass";
482
+ fail: "fail";
483
+ }>>;
484
+ }, z.core.$strict>>;
485
+ sbom: z.ZodDefault<z.ZodObject<{
486
+ format: z.ZodDefault<z.ZodEnum<{
487
+ "cyclonedx-json": "cyclonedx-json";
488
+ "spdx-json": "spdx-json";
489
+ }>>;
490
+ out: z.ZodDefault<z.ZodString>;
491
+ }, z.core.$strict>>;
492
+ smokePacked: z.ZodDefault<z.ZodObject<{
493
+ subpathsFromExports: z.ZodDefault<z.ZodBoolean>;
494
+ extraSubpaths: z.ZodDefault<z.ZodArray<z.ZodString>>;
495
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
496
+ checkExportsOnDisk: z.ZodDefault<z.ZodBoolean>;
497
+ checkTarballPurity: z.ZodDefault<z.ZodString>;
498
+ checkStylesheets: z.ZodDefault<z.ZodBoolean>;
499
+ browserConditions: z.ZodDefault<z.ZodBoolean>;
500
+ domStubs: z.ZodDefault<z.ZodBoolean>;
501
+ injectDeps: z.ZodDefault<z.ZodArray<z.ZodString>>;
502
+ }, z.core.$strict>>;
503
+ publint: z.ZodDefault<z.ZodObject<{
504
+ allowSourceTimeLinks: z.ZodDefault<z.ZodBoolean>;
505
+ sourceLinkScope: z.ZodDefault<z.ZodString>;
506
+ }, z.core.$strict>>;
507
+ rewriteImports: z.ZodDefault<z.ZodObject<{
508
+ rules: z.ZodDefault<z.ZodArray<z.ZodObject<{
509
+ match: z.ZodString;
510
+ replaceWith: z.ZodString;
511
+ literal: z.ZodOptional<z.ZodBoolean>;
512
+ quoted: z.ZodOptional<z.ZodBoolean>;
513
+ }, z.core.$strict>>>;
514
+ frameworkDetect: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
515
+ extensions: z.ZodDefault<z.ZodArray<z.ZodString>>;
516
+ deriveFromExports: z.ZodDefault<z.ZodBoolean>;
517
+ }, z.core.$strict>>;
518
+ gauntlet: z.ZodDefault<z.ZodObject<{
519
+ steps: z.ZodDefault<z.ZodArray<z.ZodString>>;
520
+ continueOnFailure: z.ZodDefault<z.ZodBoolean>;
521
+ siblingDistFreshness: z.ZodDefault<z.ZodEnum<{
522
+ check: "check";
523
+ off: "off";
524
+ build: "build";
525
+ }>>;
526
+ }, z.core.$strict>>;
527
+ }, z.core.$strict>;
528
+ type Config = z.infer<typeof ConfigSchema>;
529
+ interface LoadedConfig {
530
+ config: Config;
531
+ /** Absolute path to the config file that was read, or `null` if defaults were used. */
532
+ filePath: string | null;
533
+ }
534
+ /**
535
+ * Read `release-toolkit.config.json` if present; merge with defaults via Zod's
536
+ * `default()` mechanism. Missing config file is not an error.
537
+ */
538
+ declare function loadConfig(packageRoot: string): LoadedConfig;
539
+
540
+ /**
541
+ * `geenius-release gauntlet` — compose the configured step sequence.
542
+ *
543
+ * External steps (`lint`, `type-check`, `test:unit`, anything else) shell out
544
+ * to `pnpm <step>` so existing per-package scripts continue to work.
545
+ *
546
+ * Internal steps (`supply-chain`, `license`, `sbom`, `smoke-packed`) call the
547
+ * toolkit's `runX` functions directly — no `pnpm` overhead, full structured
548
+ * report aggregation.
549
+ */
550
+
551
+ interface RunGauntletOptions {
552
+ cwd?: string;
553
+ config?: Config;
554
+ /** Override the step list. */
555
+ steps?: readonly string[];
556
+ /** Continue running remaining steps after a failure. */
557
+ continueOnFailure?: boolean;
558
+ quiet?: boolean;
559
+ }
560
+ declare function runGauntlet(opts?: RunGauntletOptions): Promise<CommandReport>;
561
+
562
+ /**
563
+ * `geenius-release license` — forbidden-license scan over installed dependencies.
564
+ * Replaces the 36 copies of `license-check.mjs` across the ecosystem.
565
+ */
566
+
567
+ interface RunLicenseOptions {
568
+ /** Defaults to `process.cwd()` if omitted. */
569
+ cwd?: string;
570
+ /** Override loaded config. */
571
+ config?: Config["license"];
572
+ /** Override the dependency scope. */
573
+ scope?: "prod" | "all";
574
+ /** Suppress console output (for gauntlet composition). */
575
+ quiet?: boolean;
576
+ }
577
+ declare function runLicense(opts?: RunLicenseOptions): Promise<CommandReport>;
578
+
579
+ /**
580
+ * `geenius-release lint` — single canonical lint entry point.
581
+ *
582
+ * Collapses run-lint.mjs (9 pkgs) + lint-apps.mjs (4) + lint-scope.mjs (3) +
583
+ * biome-scope.mjs (5) + lint-pub.mjs (7) etc.
584
+ *
585
+ * Modes:
586
+ * default (root): root files + every in-scope variant's packageDir, plus
587
+ * discovered apps/ directories if any exist.
588
+ * --scope package: root files + variant packageDirs only.
589
+ * --scope apps: apps/* dirs derived from ui+storybook+e2e variants only.
590
+ * --scope all: everything (default behaviour, kept explicit).
591
+ * --apps: shortcut for --scope apps.
592
+ *
593
+ * Always invokes `biome check` (or `biome lint`/`biome format` via --command).
594
+ * Extra args after `--` (collected into passthrough) are forwarded.
595
+ */
596
+ type LintScope = "package" | "apps" | "all";
597
+ interface RunLintOptions {
598
+ cwd?: string;
599
+ scope?: LintScope;
600
+ /** Biome subcommand (default "check"). */
601
+ command?: "check" | "lint" | "format" | "ci";
602
+ /** Apply autofixes (`--write`). */
603
+ fix?: boolean;
604
+ /** Extra args forwarded to biome after the path list. */
605
+ passthrough?: string[];
606
+ /** Print the resolved command and exit. */
607
+ print?: boolean;
608
+ /** Limit variant collection to `implemented: true` variants. */
609
+ implementedOnly?: boolean;
610
+ }
611
+ interface LintResult {
612
+ status: "passed" | "failed" | "skipped";
613
+ command: string;
614
+ paths: string[];
615
+ exitCode: number;
616
+ }
617
+ declare function runLint(opts?: RunLintOptions): Promise<LintResult>;
618
+
619
+ /**
620
+ * `geenius-release manifest-contract` — verify that every `package.json:exports`
621
+ * target file exists on disk, that `files` patterns cover every export target,
622
+ * and that `bin` entries exist + are executable.
623
+ *
624
+ * Absorbs the inline `test -f dist/index.js && test -f dist/index.d.ts` checks
625
+ * scattered across packages (e.g. tools/devtools' `test:dist-contract`).
626
+ */
627
+
628
+ interface RunManifestContractOptions {
629
+ cwd?: string;
630
+ quiet?: boolean;
631
+ }
632
+ declare function runManifestContract(opts?: RunManifestContractOptions): Promise<CommandReport>;
633
+
634
+ /**
635
+ * `geenius-release mutation-report` — Stryker driver. Replaces 36 copies of
636
+ * `mutation-report.mjs`. Optional by default: if Stryker isn't installed or
637
+ * configured, the command skips cleanly.
638
+ */
639
+
640
+ interface RunMutationReportOptions {
641
+ cwd?: string;
642
+ /** When true (default), missing Stryker config → skipped (not failed). */
643
+ optional?: boolean;
644
+ /** Minimum mutation score required to pass (0-100). */
645
+ minScore?: number;
646
+ /** Just verify a Stryker config exists; do not invoke Stryker. */
647
+ checkConfigOnly?: boolean;
648
+ /** Fall back to `pnpm dlx --package <spec> -c "stryker run"` when the
649
+ * package's local @stryker-mutator/core isn't installed. Common form:
650
+ * `@stryker-mutator/core@9.5.0`. */
651
+ dlxSpec?: string;
652
+ /** Write a Markdown summary to this path. */
653
+ markdownOut?: string;
654
+ /** Write a structured JSON summary to this path. */
655
+ jsonOut?: string;
656
+ /** Where Stryker writes its raw report. Used to compute a fallback score
657
+ * if the run didn't print "Final mutation testing score" on stdout.
658
+ * Default: `.eval/mutation/mutation.json`. */
659
+ reportJsonPath?: string;
660
+ quiet?: boolean;
661
+ }
662
+ declare function runMutationReport(opts?: RunMutationReportOptions): Promise<CommandReport>;
663
+
664
+ /**
665
+ * `geenius-release pack-contract` — run `pnpm pack --json`, capture the
666
+ * resulting manifest into a temp directory, expose the path via
667
+ * `PACK_CONTRACT_JSON`, then run a consumer-supplied vitest config that
668
+ * asserts on the packed contents (files included, exports targets, README
669
+ * present, etc.).
670
+ *
671
+ * Generic harness — the actual contract tests are package-specific. The
672
+ * caller passes `--test-config <vitest.pack-contract.config.ts>`.
673
+ *
674
+ * Replaces local `scripts/pack-contract.mjs` shims.
675
+ */
676
+ interface RunPackContractOptions {
677
+ cwd?: string;
678
+ /** Vitest config that runs the contract assertions. Required. */
679
+ testConfig: string;
680
+ /** Pass an existing pack JSON instead of running `pnpm pack` first. */
681
+ packJson?: string;
682
+ /** Tests to run (passed to vitest as positional args). */
683
+ testFiles?: readonly string[];
684
+ }
685
+ interface PackContractResult {
686
+ status: number;
687
+ packJsonPath: string;
688
+ }
689
+ declare function runPackContract(opts: RunPackContractOptions): PackContractResult;
690
+
691
+ /**
692
+ * `geenius-release patch-dts` — post-build patcher for dist outputs.
693
+ *
694
+ * Collapses patch-dts-imports.mjs (4) + patch-solid-web-import.mjs (2) +
695
+ * the `--fix-solid-jsx-runtime` flag previously embedded in sanitize-dist.
696
+ *
697
+ * Operations (composable; pass any combination):
698
+ * --rewrite <from=to> Plain string replaceAll in .d.ts files (repeatable).
699
+ * --solid Rewrite solid-js/web → solid-js/web/dist/web.js and
700
+ * gate delegateEvents() on a window check, in .js files.
701
+ * --solid-jsx Rewrite solid-js/jsx-runtime → solid-js/h/jsx-runtime
702
+ * in .js files.
703
+ * --files <list> Operate on an explicit file list instead of walking
704
+ * a directory.
705
+ *
706
+ * Default directory is `dist/`. Walks recursively; only touches `.d.ts` for
707
+ * --rewrite, only `.js`/`.mjs`/`.cjs` for the --solid* flags.
708
+ */
709
+ interface DtsRewriteRule {
710
+ from: string;
711
+ to: string;
712
+ }
713
+ interface RunPatchDtsOptions {
714
+ cwd?: string;
715
+ /** Directory to walk (default: "dist"). Ignored when `files` is provided. */
716
+ dir?: string;
717
+ /** Explicit file list (absolute or relative to cwd). */
718
+ files?: string[];
719
+ /** Plain string replacements applied to .d.ts files. */
720
+ rewrites?: DtsRewriteRule[];
721
+ /** Apply Solid web import + delegateEvents patch to .js files. */
722
+ solid?: boolean;
723
+ /** Rewrite solid-js/jsx-runtime → solid-js/h/jsx-runtime in .js files. */
724
+ solidJsx?: boolean;
725
+ }
726
+ interface PatchDtsResult {
727
+ status: "passed" | "skipped";
728
+ filesChanged: number;
729
+ filesScanned: number;
730
+ }
731
+ declare function runPatchDts(opts?: RunPatchDtsOptions): Promise<PatchDtsResult>;
732
+
733
+ /**
734
+ * `geenius-release perf-smoke` — perf-budget harness wrapper.
735
+ * Absorbs 7 copies of `perf-smoke.mjs`.
736
+ *
737
+ * Reads `.eval/perf/results.json` produced by the package's perf harness
738
+ * (Storybook perf stories, vitest perf suite, custom Playwright harness — the
739
+ * toolkit doesn't care how the file got there) and enforces budgets from
740
+ * `release-toolkit.config.json:perf` or `perf-budgets.json` at the package
741
+ * root.
742
+ */
743
+
744
+ interface PerfBudget {
745
+ /** Symbolic metric name; matches the result file's `metric` field. */
746
+ metric: string;
747
+ /** Numerical maximum (e.g. 250 for "max 250 ms"). */
748
+ max: number;
749
+ /** Optional unit label for the report, e.g. "ms", "ops/s". */
750
+ unit?: string;
751
+ /** When set, this metric is a minimum (e.g. ops/sec) rather than a maximum. */
752
+ isMinimum?: boolean;
753
+ }
754
+ interface RunPerfSmokeOptions {
755
+ cwd?: string;
756
+ /** Path to the perf results JSON. Default: `.eval/perf/results.json`. */
757
+ resultsPath?: string;
758
+ /** Budget list. If absent, the toolkit reads `perf-budgets.json` at the
759
+ * package root, then falls back to "no enforced budgets". */
760
+ budgets?: readonly PerfBudget[];
761
+ /** Whether absent results is `failed` or `skipped`. */
762
+ optional?: boolean;
763
+ quiet?: boolean;
764
+ }
765
+ declare function runPerfSmoke(opts?: RunPerfSmokeOptions): Promise<CommandReport>;
766
+
767
+ /**
768
+ * `geenius-release pnpm-filters` — run a per-package script across the variant
769
+ * matrix.
770
+ *
771
+ * **The name is historical.** Earlier versions shelled out to
772
+ * `pnpm -r --filter ... <task>`. This version skips pnpm entirely and spawns
773
+ * each variant's `scripts.<task>` directly via `/bin/sh -c <cmd>`, which:
774
+ *
775
+ * - eliminates the ~100-300ms pnpm bootstrap per package (critical when
776
+ * fanning out 16 variants × 20 parallel agents);
777
+ * - keeps `package.json` script semantics intact (shell pipes, &&, env
778
+ * substitution all work because we hand the raw command to sh);
779
+ * - augments PATH with each variant's `node_modules/.bin` and every
780
+ * ancestor `node_modules/.bin` so locally-installed tools resolve the
781
+ * same way pnpm exec would have resolved them.
782
+ *
783
+ * Execution modes (CLI surface is unchanged from the pnpm-era):
784
+ * - **parallel** (default): launch all variants concurrently, optionally
785
+ * capped by `--workspace-concurrency=N`. Stdout/stderr prefixed per pkg.
786
+ * - **sequential**: one variant at a time, optional shared-first + kind
787
+ * tiering + heartbeat.
788
+ * - **shared-then-parallel**: shared first sequentially, then everything
789
+ * else in parallel.
790
+ *
791
+ * `--prebuild <dir>` runs `<dir>`'s `build` script (always `build`, not the
792
+ * requested task) before the main fan-out, and removes `<dir>` from the main
793
+ * fan-out when task is also build.
794
+ */
795
+ interface RunPnpmFiltersOptions {
796
+ cwd?: string;
797
+ task: string;
798
+ includeMissing?: boolean;
799
+ /** Limit fan-out to variants flagged `implemented: true`. */
800
+ implementedOnly?: boolean;
801
+ /** Skip variants whose package.json has no entry for `task` (default: true). */
802
+ ifPresent?: boolean;
803
+ /** Force unbounded parallelism (alias for `workspaceConcurrency: undefined`). */
804
+ parallel?: boolean;
805
+ /** Cap concurrent in-flight spawns in parallel mode (string for CLI parity). */
806
+ workspaceConcurrency?: string;
807
+ /** Print the resolved per-variant invocations and exit (no spawns). */
808
+ print?: boolean;
809
+ kinds?: readonly string[];
810
+ /** Forward extra arguments after the script body. Joined with space and
811
+ * appended; the package script receives them via `$@`-like shell expansion. */
812
+ passthrough?: readonly string[];
813
+ /** Filter variants to those declaring `variant.tests.<key> === true`. */
814
+ requires?: readonly string[];
815
+ /** Sequential mode (one variant at a time). Overrides --parallel. */
816
+ sequential?: boolean;
817
+ /** Execution mode (takes precedence over `sequential`/`parallel`). */
818
+ mode?: "parallel" | "sequential" | "shared-then-parallel";
819
+ /** When sequential or shared-then-parallel, run this packageDir first. */
820
+ sharedFirst?: string;
821
+ /** Heartbeat interval (ms) when sequential, so CI doesn't kill a quiet job. */
822
+ heartbeatMs?: number;
823
+ /** Order variant kinds into tiers (sequential mode only). */
824
+ sequentialKindOrder?: readonly (readonly string[])[];
825
+ /** Build `<dir>` (always `build`, not the requested task) before main fan-out.
826
+ * When `task === "build"`, the main fan-out excludes `<dir>`. */
827
+ prebuild?: string;
828
+ }
829
+ interface PnpmFiltersResult {
830
+ status: number;
831
+ /** Per-variant resolved invocations. Each entry: `[label, command]`. */
832
+ invocations: {
833
+ label: string;
834
+ cwd: string;
835
+ command: string;
836
+ }[];
837
+ }
838
+ declare function runPnpmFilters(opts: RunPnpmFiltersOptions): Promise<PnpmFiltersResult>;
839
+
840
+ /**
841
+ * `geenius-release publint` — run publint against the package's packed tarball.
842
+ * Replaces ~17 scripts across 4 filename variations in the legacy tree
843
+ * (`publint-package.mjs`, `publint-packed.mjs`, `publint-check.mjs`, `publint.mjs`).
844
+ *
845
+ * publint is resolved from the package's local `node_modules/.bin` and spawned
846
+ * directly (skipping `pnpm exec`'s ~300ms bootstrap). If the binary isn't
847
+ * reachable, we report `missing` and let the config decide whether that's an
848
+ * optional skip.
849
+ */
850
+
851
+ interface RunPublintOptions {
852
+ cwd?: string;
853
+ /** Allow publint to be missing without failing. Default: false (publint should always pass). */
854
+ optional?: boolean;
855
+ /** Tolerance config for source-time `link:` deps. */
856
+ config?: Config["publint"];
857
+ quiet?: boolean;
858
+ }
859
+ declare function runPublint(opts?: RunPublintOptions): Promise<CommandReport>;
860
+
861
+ /**
862
+ * `geenius-release rewrite-imports` — post-build codemod that rewrites
863
+ * private subpath imports in a variant's built `dist/` so packed tarballs
864
+ * don't need to advertise internal `./shared` (or similar) exports.
865
+ *
866
+ * Replaces ~36 copies of `rewrite-private-imports.mjs`. Rules are
867
+ * config-driven and token-aware (`${packageName}`, `${framework}`,
868
+ * `${variant}`) so the same toolkit serves every Geenius package that
869
+ * keeps shared code under `packages/shared/` and per-framework variants
870
+ * under `packages/<variant>/`.
871
+ */
872
+
873
+ interface RewriteRule {
874
+ /** Literal specifier to find. Token-expanded before matching. */
875
+ match: string;
876
+ /** Replacement. Token-expanded. When `literal` is false (default), treated
877
+ * as a path relative to packageRoot and converted into a module specifier
878
+ * relative to the variant's `dist/`. When `literal` is true, used as-is —
879
+ * useful for JSDoc / comment cleanup ("internal-name → public-name"). */
880
+ replaceWith: string;
881
+ /** If true, `replaceWith` is used as literal text (no path resolution). */
882
+ literal?: boolean;
883
+ /** If true, only quoted occurrences are matched (both `"<match>"` and
884
+ * `'<match>'`). Use this for import-specifier rewrites that must not
885
+ * touch identical strings in JSDoc / comments. */
886
+ quoted?: boolean;
887
+ }
888
+ interface RunRewriteImportsOptions {
889
+ cwd?: string;
890
+ /** Variant directory, relative to packageRoot (e.g. `packages/react`). */
891
+ variantDir: string;
892
+ /** Override config rules. */
893
+ rules?: readonly RewriteRule[];
894
+ /** Override framework detection. Map of framework name → variant-basename regex. */
895
+ frameworkDetect?: Record<string, string>;
896
+ /** Explicit framework name (skips detection). */
897
+ framework?: string;
898
+ /** File extensions to rewrite. Default: `[".js", ".d.ts"]`. */
899
+ extensions?: readonly string[];
900
+ /** If true, generate additional literal rules from the root manifest's
901
+ * `exports` map: for every `packages/<name>` referenced from an exports
902
+ * target, map the private workspace name (read from `packages/<name>/
903
+ * package.json`) to the public root-subpath specifier. Useful when
904
+ * consumers must not see internal workspace package names in published
905
+ * declaration files. Added after any explicitly configured rules. */
906
+ deriveFromExports?: boolean;
907
+ /** Built-in preset names to layer on. Currently: `solid-web` (rewrite
908
+ * `solid-js/web` to `solid-js/web/dist/web.js` so Node ESM consumers can
909
+ * resolve it without subpath redirects). Presets append to the rule list. */
910
+ presets?: readonly "solid-web"[];
911
+ config?: Config["rewriteImports"];
912
+ quiet?: boolean;
913
+ }
914
+ declare function runRewriteImports(opts: RunRewriteImportsOptions): Promise<CommandReport>;
915
+
916
+ /**
917
+ * `geenius-release run-scripts <s1> <s2> …` — run multiple top-level
918
+ * `package.json` scripts sequentially in the package root, with PATH
919
+ * augmented to include `node_modules/.bin`. Stops on the first failure
920
+ * and propagates the failing exit code.
921
+ *
922
+ * Replaces local `_run-root-scripts.mjs` shims that exist in adapters and
923
+ * similar packages, where a single command needs to chain build → tests
924
+ * → exports → dist-contract in the same shell context.
925
+ */
926
+ interface RunScriptsOptions {
927
+ cwd?: string;
928
+ scripts: readonly string[];
929
+ /** Stop on first failure (default: true). */
930
+ stopOnFailure?: boolean;
931
+ /** Don't actually spawn; print the command list. */
932
+ print?: boolean;
933
+ }
934
+ interface RunScriptsResult {
935
+ status: number;
936
+ /** Names of scripts that ran (including the failing one if applicable). */
937
+ ran: string[];
938
+ /** Name of the failing script, if any. */
939
+ failedAt?: string;
940
+ }
941
+ declare function runScripts(opts: RunScriptsOptions): Promise<RunScriptsResult>;
942
+
943
+ /**
944
+ * `geenius-release sanitize-dist` — strip leaky tsup artifacts from built JS.
945
+ *
946
+ * Collapses sanitize-dist-comments.mjs (3) + sanitize-dist.mjs (2).
947
+ *
948
+ * Operations (composable):
949
+ * --comments (default on) Strip `// src/...` / `// .../src/...` comments tsup leaves at
950
+ * the top of bundled chunks (they expose workspace
951
+ * source paths).
952
+ * --maps Strip `//# sourceMappingURL=` comments.
953
+ * --fix-solid-jsx-runtime Rewrite solid-js/jsx-runtime → solid-js/h/jsx-runtime.
954
+ *
955
+ * Walks `dist/` (override with `dir`) and only touches `.js`, `.cjs`, `.mjs`.
956
+ */
957
+ interface RunSanitizeDistOptions {
958
+ cwd?: string;
959
+ dir?: string;
960
+ /** Default true. Strip `// .../src/...` source-path comments. */
961
+ comments?: boolean;
962
+ /** Default false. Strip sourceMappingURL comments. */
963
+ maps?: boolean;
964
+ /** Default false. Rewrite solid-js/jsx-runtime to runtime/h variant. */
965
+ fixSolidJsxRuntime?: boolean;
966
+ }
967
+ interface SanitizeDistResult {
968
+ status: "passed" | "skipped";
969
+ filesScanned: number;
970
+ filesChanged: number;
971
+ }
972
+ declare function runSanitizeDist(opts?: RunSanitizeDistOptions): Promise<SanitizeDistResult>;
973
+
974
+ /**
975
+ * `geenius-release sbom` — emit a CycloneDX 1.5 JSON SBOM from pnpm-lock.yaml.
976
+ * Replaces the 36 copies of `sbom.mjs`.
977
+ *
978
+ * Implementation strategy: parse the lockfile YAML by line (no dependency on a
979
+ * full YAML parser — pnpm-lock.yaml has a stable, simple shape since v9).
980
+ * For SPDX format we shell out to `syft` if available; otherwise we report
981
+ * SPDX as `missing` per the optional-scanner policy.
982
+ */
983
+
984
+ interface RunSbomOptions {
985
+ cwd?: string;
986
+ config?: Config["sbom"];
987
+ /** Override output path. */
988
+ out?: string;
989
+ /** Override format. */
990
+ format?: "cyclonedx-json" | "spdx-json";
991
+ quiet?: boolean;
992
+ }
993
+ declare function runSbom(opts?: RunSbomOptions): Promise<CommandReport>;
994
+
995
+ /**
996
+ * `geenius-release size-check` — size-limit driver. Replaces 13 copies of
997
+ * `size-check.mjs`. Reads the package's `size-limit` config (either from
998
+ * `package.json:size-limit` or `size-limit.config.{js,mjs,ts}`) and runs the
999
+ * `size-limit` binary; passing means every entry is under its budget.
1000
+ */
1001
+
1002
+ interface RunSizeCheckOptions {
1003
+ cwd?: string;
1004
+ /** When the size-limit binary or config is absent: `false` → step is `missing`
1005
+ * and command fails. `true` (default) → step is `skipped` and command passes.
1006
+ * This mirrors `mutation-report` — size-limit is opt-in tooling, not every
1007
+ * package adopts it. */
1008
+ optional?: boolean;
1009
+ /** Additional flags to pass to size-limit (e.g. `--why`). */
1010
+ extraArgs?: readonly string[];
1011
+ quiet?: boolean;
1012
+ }
1013
+ declare function runSizeCheck(opts?: RunSizeCheckOptions): Promise<CommandReport>;
1014
+
1015
+ /**
1016
+ * `geenius-release size-limit-config` — generate size-limit entries from
1017
+ * `variants.json` and the root manifest's `exports` map.
1018
+ *
1019
+ * For every variant whose `packageDir` is referenced in `root.exports` (i.e.
1020
+ * actually shipped) and that declares `budget.gzip`, emit a size-limit entry:
1021
+ * { name, path: "<packageDir>/dist/index.js", ignore: [...peerDeps], limit }
1022
+ *
1023
+ * Variants without `budget.gzip` cause an error when they're in the exported
1024
+ * set — this is the same invariant adapters' local `size-limit-config.mjs`
1025
+ * enforces. Replaces ~5 copies across the ecosystem.
1026
+ *
1027
+ * Emits JSON to stdout; consumers pipe it into their `.size-limit.cjs` /
1028
+ * `size-limit.config.mjs` (typically `module.exports = JSON.parse(read(...))`).
1029
+ */
1030
+ interface RunSizeLimitConfigOptions {
1031
+ cwd?: string;
1032
+ /** Pretty-print JSON. Default: true. */
1033
+ pretty?: boolean;
1034
+ /** Match variants by exact `packageDir`. Default: derive from root exports. */
1035
+ packageDirs?: readonly string[];
1036
+ }
1037
+ interface SizeLimitEntry {
1038
+ name: string;
1039
+ path: string;
1040
+ ignore: string[];
1041
+ limit: string;
1042
+ }
1043
+ declare function runSizeLimitConfig(opts?: RunSizeLimitConfigOptions): {
1044
+ ok: boolean;
1045
+ entries: SizeLimitEntry[];
1046
+ output: string;
1047
+ };
1048
+
1049
+ /**
1050
+ * `geenius-release smoke-packed` — pack the package, install the tarball into
1051
+ * an ephemeral tmpdir, and dynamic-import every subpath in `package.json:exports`.
1052
+ *
1053
+ * Replaces the 36 copies of `smoke-packed-imports.mjs` (the heaviest legacy
1054
+ * script at ~286 LOC/copy = 10,318 total LOC absorbed).
1055
+ */
1056
+
1057
+ interface RunSmokePackedOptions {
1058
+ cwd?: string;
1059
+ config?: Config["smokePacked"];
1060
+ /** Limit to a subset of subpaths. */
1061
+ subpaths?: readonly string[];
1062
+ quiet?: boolean;
1063
+ /** CLI-only overrides (mirror config fields). */
1064
+ checkExportsOnDisk?: boolean;
1065
+ checkTarballPurity?: string;
1066
+ checkStylesheets?: boolean;
1067
+ browserConditions?: boolean;
1068
+ domStubs?: boolean;
1069
+ injectDeps?: readonly string[];
1070
+ }
1071
+ declare function runSmokePacked(opts?: RunSmokePackedOptions): Promise<CommandReport>;
1072
+
1073
+ /**
1074
+ * `geenius-release storybook` — build + test-runner orchestration for every
1075
+ * Storybook app declared in `release-toolkit.config.json:storybook.apps`.
1076
+ *
1077
+ * Absorbs ~28 scripts across 5 filename variations (`storybook-runner.mjs`,
1078
+ * `storybook-test-runner.mjs`, `test-storybook-static.mjs`, `storybook-build.mjs`,
1079
+ * `storybook-apps.mjs`).
1080
+ *
1081
+ * Each app is identified by a relative path to its directory; the toolkit
1082
+ * invokes `pnpm --dir <path> <action>` for each. Actions are configurable
1083
+ * (default: build then test:storybook).
1084
+ */
1085
+
1086
+ interface RunStorybookOptions {
1087
+ cwd?: string;
1088
+ /** Relative paths to Storybook app directories. If omitted, falls back to
1089
+ * globbing `apps/storybook-*` at the package root. */
1090
+ apps?: readonly string[];
1091
+ /** Lifecycle action to run per app. Default: `["build", "test:storybook"]`. */
1092
+ actions?: readonly string[];
1093
+ /** Limit to a subset of apps via a substring filter. */
1094
+ filter?: string;
1095
+ /** Soft-skip apps that don't have the requested script. Default: true. */
1096
+ skipIfMissingScript?: boolean;
1097
+ /** Continue with the next app after a failure. */
1098
+ continueOnFailure?: boolean;
1099
+ /** When set, run the toolkit's built-in static smoke (Playwright + http
1100
+ * server) instead of (or after) shelling out to `pnpm test:storybook`.
1101
+ * `replace` skips per-app `test:storybook`, `after` runs it then smoke,
1102
+ * `only` skips `build` too. Default: undefined (legacy behavior). */
1103
+ staticSmoke?: "replace" | "after" | "only";
1104
+ /** Per-app runner. `static-smoke` is the toolkit's built-in Playwright +
1105
+ * http-server smoke (equivalent to `staticSmoke: "replace"`).
1106
+ * `test-runner` invokes `@storybook/test-runner` against a served
1107
+ * built Storybook. `vitest` runs the app's `test:storybook` script
1108
+ * (which typically points at a Vitest browser-mode config).
1109
+ * When set, `staticSmoke` is ignored and a single build step runs
1110
+ * before the chosen runner. */
1111
+ runner?: "static-smoke" | "test-runner" | "vitest";
1112
+ /** Story ids every Storybook must include during static smoke. */
1113
+ requiredStoryIds?: readonly string[];
1114
+ /** Discover apps from variants.json instead of auto-globbing apps/storybook-*.
1115
+ * Reads variants where `storybook` field is set; respects `published` if
1116
+ * `fromVariantsScope: "published"` is also set. */
1117
+ fromVariants?: boolean;
1118
+ /** When `fromVariants` is true: `all` (default) includes every variant
1119
+ * with a `storybook` field; `published` includes only variants with
1120
+ * `published: true`. */
1121
+ fromVariantsScope?: "all" | "published";
1122
+ /** When set, assert per-app structural shape (required + forbidden files,
1123
+ * required story titles in the built index.json). Same intent as the
1124
+ * per-package `scripts/storybook-app-smoke.mjs` shim. */
1125
+ checkShape?: StorybookShapeSpec;
1126
+ quiet?: boolean;
1127
+ }
1128
+ interface StorybookShapeSpec {
1129
+ /** Paths (relative to the app dir) that must exist. */
1130
+ requiredFiles?: readonly string[];
1131
+ /** Paths (relative to the app dir) that must NOT exist. */
1132
+ forbiddenFiles?: readonly string[];
1133
+ /** Story titles (from index.json `entries[].title`) that must be present. */
1134
+ requiredTitles?: readonly string[];
1135
+ }
1136
+ declare function runStorybook(opts?: RunStorybookOptions): Promise<CommandReport>;
1137
+
1138
+ /**
1139
+ * `geenius-release supply-chain` — pnpm audit + osv-scanner + Socket + license,
1140
+ * all configurable required/optional. Replaces the 26 scripts across 7
1141
+ * filename variations in the legacy tree.
1142
+ */
1143
+
1144
+ interface RunSupplyChainOptions {
1145
+ cwd?: string;
1146
+ config?: Config["supplyChain"];
1147
+ /** Inherited from the parent License command settings, when invoked from gauntlet. */
1148
+ licenseConfig?: Config["license"];
1149
+ quiet?: boolean;
1150
+ }
1151
+ declare function runSupplyChain(opts?: RunSupplyChainOptions): Promise<CommandReport>;
1152
+
1153
+ /**
1154
+ * `geenius-release type-check` — run a per-variant type-check command,
1155
+ * with a fallback chain. For each variant declaring a `packageDir`:
1156
+ *
1157
+ * 1. If the variant's `package.json` has a `type-check` script, run it.
1158
+ * 2. Otherwise, if it has a `lint` script, run that.
1159
+ * 3. Otherwise, run `tsc --noEmit` from the variant directory.
1160
+ *
1161
+ * PATH is augmented to include both the variant's and root's `node_modules/.bin`
1162
+ * so locally-installed `tsc` resolves correctly. Replaces
1163
+ * `scripts/type-check-packages.mjs` (78 LOC × several packages).
1164
+ */
1165
+ interface RunTypeCheckOptions {
1166
+ cwd?: string;
1167
+ /** Continue with the next variant after a failure (default: false). */
1168
+ continueOnFailure?: boolean;
1169
+ /** Include variants marked inScope:false (default: true — type-checking
1170
+ * out-of-scope code surfaces drift early). */
1171
+ includeOutOfScope?: boolean;
1172
+ /** Run this packageDir first (typical: packages/shared). Default: undefined. */
1173
+ sharedFirst?: string;
1174
+ /** Don't spawn; print the resolved command list. */
1175
+ print?: boolean;
1176
+ }
1177
+ interface TypeCheckResult {
1178
+ status: number;
1179
+ results: {
1180
+ packageDir: string;
1181
+ command: string;
1182
+ status: number;
1183
+ }[];
1184
+ }
1185
+ declare function runTypeCheck(opts?: RunTypeCheckOptions): Promise<TypeCheckResult>;
1186
+
1187
+ /**
1188
+ * `geenius-release variants` — print the package's variant matrix.
1189
+ *
1190
+ * Subcommands:
1191
+ * - list (default) Emit `manifest.variants` as JSON.
1192
+ * - missing Emit only required variants whose `packageDir` is absent.
1193
+ * - published-subpaths Emit `{variant,subpath}[]` for every published subpath.
1194
+ * - ui Emit only UI-kind variants.
1195
+ * - db Emit only db-provider variants.
1196
+ * - storybook-apps Emit `{variant,app,appDir}[]` for every Storybook host.
1197
+ *
1198
+ * Replaces 43 copies of `scripts/_variants.mjs`.
1199
+ */
1200
+ interface RunVariantsOptions {
1201
+ cwd?: string;
1202
+ subcommand?: "list" | "missing" | "published-subpaths" | "ui" | "db" | "storybook-apps" | "check";
1203
+ includeOutOfScope?: boolean;
1204
+ /** Pretty-print JSON. Default: true. */
1205
+ pretty?: boolean;
1206
+ /** `check` subcommand: require every entry with `required: true` (or
1207
+ * unspecified `required`) to have a `packageDir` that exists on disk. */
1208
+ requireAll?: boolean;
1209
+ }
1210
+ declare function runVariants(opts?: RunVariantsOptions): {
1211
+ ok: boolean;
1212
+ output: string;
1213
+ };
1214
+
1215
+ /**
1216
+ * `geenius-release vitest-browser-prepare` — vitest browser-mode prepare plugin.
1217
+ *
1218
+ * Collapses vitest-browser-prepare-retry.ts copies across 4 packages.
1219
+ *
1220
+ * Exposed both as a programmatic plugin factory (for `vitest.config.ts`) and as
1221
+ * a CLI command that prints the plugin source for ad-hoc copy/integration. In
1222
+ * practice every package should import the factory, not the CLI; the CLI is
1223
+ * just an inspection escape hatch.
1224
+ */
1225
+ interface VitestBrowserPreparePlugin {
1226
+ name: string;
1227
+ transformIndexHtml: {
1228
+ order: "pre";
1229
+ handler: () => {
1230
+ tag: string;
1231
+ injectTo: "head-prepend";
1232
+ children: string;
1233
+ }[];
1234
+ };
1235
+ }
1236
+ /**
1237
+ * Returns a Vitest browser-mode plugin that proxies `BroadcastChannel`
1238
+ * construction inside the harness iframe so prepare/execute/cleanup messages
1239
+ * emitted before the iframe's listener is attached are still delivered.
1240
+ *
1241
+ * Mirrors the per-package `vitestBrowserPrepareRetry()` factory verbatim so
1242
+ * existing vitest configs can swap `from "./scripts/..."` for `from
1243
+ * "@geenius/release-toolkit/vitest"` without behavioural drift.
1244
+ */
1245
+ declare function vitestBrowserPrepareRetry(): VitestBrowserPreparePlugin;
1246
+ interface RunVitestBrowserPrepareOptions {
1247
+ /** Print the injected script body to stdout (CLI inspection). */
1248
+ print?: boolean;
1249
+ }
1250
+ declare function runVitestBrowserPrepare(opts?: RunVitestBrowserPrepareOptions): {
1251
+ status: "passed";
1252
+ source: string;
1253
+ };
1254
+
1255
+ /**
1256
+ * Centralized environment detection. Every subcommand reads its strictness
1257
+ * dials from here instead of inspecting `process.env` ad-hoc.
1258
+ */
1259
+ interface EnvSnapshot {
1260
+ /** True if `CI` is set to a truthy value (`"1"`, `"true"`, `"yes"`). */
1261
+ ci: boolean;
1262
+ /** True when `SOCKET_API_TOKEN` is set; informs the supply-chain scanner. */
1263
+ socketTokenPresent: boolean;
1264
+ /** Coarse strictness override, parsed from `GEENIUS_RELEASE_STRICTNESS`.
1265
+ * - `"strict"`: every optional/skipIfX policy escalates one level.
1266
+ * - `"lenient"`: every optional/skipIfX policy de-escalates one level.
1267
+ * - `undefined`: use configured defaults. */
1268
+ strictness: "strict" | "lenient" | undefined;
1269
+ /** Per-scanner override: `GEENIUS_SUPPLY_CHAIN_<NAME>=off|optional|required`. */
1270
+ supplyChainOverrides: Record<string, "off" | "optional" | "required">;
1271
+ }
1272
+ /**
1273
+ * Read the environment once. Pure with respect to `env`; callers in tests can
1274
+ * pass a custom object instead of `process.env`.
1275
+ */
1276
+ declare function readEnv(env?: NodeJS.ProcessEnv): EnvSnapshot;
1277
+
1278
+ /**
1279
+ * Canonical exit codes. Stable across versions — adding a new code is a major
1280
+ * bump. CI integrations rely on these.
1281
+ */
1282
+ declare const ExitCode: {
1283
+ readonly OK: 0;
1284
+ readonly REQUIRED_FAILURE: 1;
1285
+ readonly CONFIG_ERROR: 2;
1286
+ readonly ENV_ERROR: 3;
1287
+ readonly INTERNAL_BUG: 4;
1288
+ };
1289
+ type ExitCode = (typeof ExitCode)[keyof typeof ExitCode];
1290
+ /**
1291
+ * Errors the CLI knows how to translate into a non-zero exit code. Any other
1292
+ * thrown value is an unexpected failure (exit code 4).
1293
+ */
1294
+ declare class ReleaseToolkitError extends Error {
1295
+ readonly code: ExitCode;
1296
+ readonly hint?: string | undefined;
1297
+ constructor(message: string, code: ExitCode, hint?: string | undefined);
1298
+ }
1299
+
1300
+ /**
1301
+ * Canonical path resolution. Every command and lib reads paths through here so
1302
+ * relocating the report directory or the lockfile name is a one-line edit.
1303
+ */
1304
+ interface ResolvedPaths {
1305
+ /** Absolute path to the package root (the directory containing package.json). */
1306
+ packageRoot: string;
1307
+ /** Absolute path to the package's pnpm-lock.yaml. */
1308
+ lockfile: string;
1309
+ /** Absolute path to the package's package.json. */
1310
+ packageJson: string;
1311
+ /** Absolute path to the package's node_modules root. */
1312
+ nodeModules: string;
1313
+ /** Absolute path to `.eval/release-toolkit/`. Reports go here. */
1314
+ reportDir: string;
1315
+ }
1316
+ /**
1317
+ * Resolve filesystem paths relative to a starting cwd. Walks up to find the
1318
+ * first directory containing both `package.json` and `pnpm-lock.yaml`. This
1319
+ * matches how `pnpm` itself locates package roots and lets the CLI be invoked
1320
+ * from a sub-directory.
1321
+ */
1322
+ declare function resolvePaths(startCwd?: string): ResolvedPaths;
1323
+
1324
+ /**
1325
+ * Rich variants loader — replaces the per-package `_variants.mjs` helper
1326
+ * (43 copies across the workspace).
1327
+ *
1328
+ * Reads `variants.json` at the package root and returns typed variant
1329
+ * objects with derived `packagePath`/`exists`/`subpaths` fields, plus
1330
+ * helper queries (`packageVariants`, `uiVariants`, `dbProviderVariants`,
1331
+ * `storybookApps`, `publishedSubpaths`, …). Honors the
1332
+ * OMEGA_INCLUDE_OUT_OF_SCOPE env flag the legacy scripts depend on.
1333
+ */
1334
+ interface RichVariantTestsConfig {
1335
+ unit?: boolean;
1336
+ coverage?: Record<string, number>;
1337
+ [key: string]: unknown;
1338
+ }
1339
+ interface RichVariant {
1340
+ name: string;
1341
+ kind: string;
1342
+ framework?: string;
1343
+ packageDir?: string;
1344
+ workspace?: string;
1345
+ driver?: string;
1346
+ subpath?: string;
1347
+ aliases?: string[];
1348
+ published?: boolean;
1349
+ storybook?: string;
1350
+ tests?: RichVariantTestsConfig;
1351
+ inScope?: boolean;
1352
+ /** Derived: absolute path to the variant directory. */
1353
+ packagePath: string | null;
1354
+ /** Derived: whether `packagePath` exists on disk. */
1355
+ exists: boolean;
1356
+ /** Derived: subpath + aliases concatenated. */
1357
+ subpaths: string[];
1358
+ [key: string]: unknown;
1359
+ }
1360
+ interface RichVariantsManifest {
1361
+ package: string;
1362
+ rootDir: string;
1363
+ variants: RichVariant[];
1364
+ coverage?: {
1365
+ reference?: Record<string, number>;
1366
+ library?: Record<string, number>;
1367
+ provider?: Record<string, number>;
1368
+ };
1369
+ [key: string]: unknown;
1370
+ }
1371
+ interface LoadRichVariantsOptions {
1372
+ /** Override the package root (otherwise the caller's cwd is used). */
1373
+ rootDir?: string;
1374
+ /** Force-include out-of-scope variants regardless of env. */
1375
+ includeOutOfScope?: boolean;
1376
+ }
1377
+ declare function loadRichVariants(opts?: LoadRichVariantsOptions): RichVariantsManifest;
1378
+ interface VariantQueryOptions extends LoadRichVariantsOptions {
1379
+ includeMissing?: boolean;
1380
+ publishedOnly?: boolean;
1381
+ kinds?: readonly string[];
1382
+ /** Only include variants flagged `implemented: true`. */
1383
+ implementedOnly?: boolean;
1384
+ }
1385
+ declare function packageVariants(opts?: VariantQueryOptions): RichVariant[];
1386
+ declare function variantsByKind(kind: string, opts?: LoadRichVariantsOptions): RichVariant[];
1387
+ declare function uiVariants(opts?: VariantQueryOptions): RichVariant[];
1388
+ declare function dbProviderVariants(opts?: LoadRichVariantsOptions): RichVariant[];
1389
+ declare function publishedSubpaths(opts?: LoadRichVariantsOptions): {
1390
+ variant: RichVariant;
1391
+ subpath: string;
1392
+ }[];
1393
+ declare function storybookVariants(opts?: LoadRichVariantsOptions): RichVariant[];
1394
+ declare function storybookApps(opts?: LoadRichVariantsOptions): {
1395
+ variant: RichVariant;
1396
+ app: string;
1397
+ appDir: string;
1398
+ }[];
1399
+ declare function missingRequiredVariants(opts?: LoadRichVariantsOptions): RichVariant[];
1400
+
1401
+ export { type BudgetRow, type BundleBudgetsResult, type CommandReport, type CommandStatus, type Config, ConfigSchema, type ConvexBuildResult, type ConvexCodegenResult, type CoverageResult, type DbMigrationsResult, type DtsRewriteRule, type E2EResult, type EnvSnapshot, ExitCode, type LintResult, type PackContractResult, type PatchDtsResult, type PnpmFiltersResult, ReleaseToolkitError, type ResolvedPaths, type RewriteRule, type RichVariant, type RichVariantsManifest, type RunA11yReportOptions, type RunAttwOptions, type RunBundleBudgetsOptions, type RunConvexBuildOptions, type RunConvexCodegenOptions, type RunCoverageOptions, type RunCoverageReportOptions, type RunDbMigrationsOptions, type RunDiffCoverageOptions, type RunE2EOptions, type RunGauntletOptions, type RunLicenseOptions, type RunLintOptions, type RunManifestContractOptions, type RunMutationReportOptions, type RunPackContractOptions, type RunPatchDtsOptions, type RunPerfSmokeOptions, type RunPnpmFiltersOptions, type RunPublintOptions, type RunRewriteImportsOptions, type RunSanitizeDistOptions, type RunSbomOptions, type RunScriptsOptions, type RunScriptsResult, type RunSizeCheckOptions, type RunSizeLimitConfigOptions, type RunSmokePackedOptions, type RunStorybookOptions, type RunSupplyChainOptions, type RunTypeCheckOptions, type RunVariantsOptions, type RunVitestBrowserPrepareOptions, type SanitizeDistResult, type ScannerState, type SizeLimitEntry, type StepReport, type StepStatus, type TypeCheckResult, type VitestBrowserPreparePlugin, dbProviderVariants, loadConfig, loadRichVariants, missingRequiredVariants, packageVariants, publishedSubpaths, readEnv, resolvePaths, runA11yReport, runAttw, runBundleBudgets, runConvexBuild, runConvexCodegen, runCoverage, runCoverageReport, runDbMigrations, runDiffCoverage, runE2E, runGauntlet, runLicense, runLint, runManifestContract, runMutationReport, runPackContract, runPatchDts, runPerfSmoke, runPnpmFilters, runPublint, runRewriteImports, runSanitizeDist, runSbom, runScripts, runSizeCheck, runSizeLimitConfig, runSmokePacked, runStorybook, runSupplyChain, runTypeCheck, runVariants, runVitestBrowserPrepare, storybookApps, storybookVariants, uiVariants, variantsByKind, vitestBrowserPrepareRetry };