@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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,335 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@geenius/release-toolkit` are documented in this file.
4
+ The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/);
5
+ versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.9.2] — 2026-05-18
8
+
9
+ ### Fixed
10
+
11
+ - **Hide optional `@playwright/test` dynamic import from consumer-side static
12
+ analyzers.** When a consuming package's vitest config imported anything
13
+ from `@geenius/release-toolkit` (e.g. `packageVariants`), vite's
14
+ `import-analysis` plugin tried to resolve `@playwright/test` through the
15
+ toolkit's dist and failed with "Failed to resolve import @playwright/test"
16
+ even when the consumer hadn't asked to use the storybook static-smoke
17
+ command at all. The dynamic import now uses a variable specifier
18
+ (`const s = "@playwright/test"; await import(s)`) — semantically
19
+ identical, but invisible to static analyzers.
20
+
21
+ ## [0.9.1] — 2026-05-18
22
+
23
+ ### Fixed
24
+
25
+ - **`lint` now accepts positional passthrough args.** Previously `geenius-release
26
+ lint -- --error-on-warnings` rejected with "too many arguments". The command
27
+ now declares `[passthrough...]` and forwards everything after the options
28
+ (and after a literal `--`) to biome. Unblocks geenie / config migrations
29
+ that want to enforce `--error-on-warnings` in their gauntlets.
30
+
31
+ ## [0.9.0] — 2026-05-18
32
+
33
+ ### Added — smoke-packed UI/workspace-dep enhancements
34
+
35
+ Surfaced from auditing the 34 packages each carrying their own
36
+ ~80-400 LOC `scripts/smoke-packed-imports.mjs` variants. The toolkit's
37
+ existing `smoke-packed` already handled pack → install → import; the
38
+ per-package divergence was all in extra checks and UI runtime mocks.
39
+ Six additive features absorb that divergence:
40
+
41
+ - **`--check-exports-on-disk`** — extract tarball + verify every declared
42
+ `exports[*].{types,import,default}` target file exists.
43
+ - **`--check-tarball-purity <regex>`** — every tar entry must match the
44
+ pattern; reports unexpected files (catches accidental dev-asset leaks).
45
+ - **`--check-stylesheets`** — file-exists verification for `.css` export
46
+ targets (no import; matters for CSS-only subpaths).
47
+ - **`--browser-conditions`** — pass `--conditions=browser` to the import
48
+ probe so browser/server condition splits resolve the browser branch.
49
+ - **`--dom-stubs`** — prepend DOM stubs (window, document, matchMedia,
50
+ HTMLElement, …) to the probe so UI imports with module-evaluation-time
51
+ DOM access don't crash.
52
+ - **`--inject-deps <list>`** — comma-separated workspace package names to
53
+ symlink into the consumer's `node_modules` before the probe runs. Each
54
+ name resolves against the sibling packages root via the
55
+ `@geenius/<x>` → `<siblingsRoot>/geenius-<x>` convention. Use for
56
+ `link:` workspace deps that can't be satisfied from a registry.
57
+
58
+ All six are also available as `release-toolkit.config.json#smokePacked`
59
+ fields (`checkExportsOnDisk`, `checkTarballPurity`, `checkStylesheets`,
60
+ `browserConditions`, `domStubs`, `injectDeps`); CLI flags take precedence
61
+ per-field.
62
+
63
+ Distinct from `pack-contract` (which delegates assertions to a vitest
64
+ config) — these flags are the convention-over-configuration path for the
65
+ common UI smoke-test shape.
66
+
67
+ ## [0.8.0] — 2026-05-17
68
+
69
+ ### Performance (major)
70
+
71
+ - **`pnpm-filters` no longer shells out to pnpm.** The previous implementation
72
+ invoked `pnpm -r --filter ./pkg run <task>` per fan-out, paying a
73
+ ~100-300ms pnpm bootstrap per package. The new implementation reads each
74
+ variant's `package.json`, looks up `scripts.<task>`, and spawns it
75
+ directly via `/bin/sh -c <cmd>` in the variant's cwd with PATH augmented
76
+ to include every ancestor `node_modules/.bin`. Result:
77
+ - 16 variants × parallel mode goes from ~3-4s of pure pnpm overhead to
78
+ ~50ms of orchestration overhead
79
+ - parallel mode no longer requires pnpm to be installed at all
80
+ - all `package.json` script semantics (shell pipes, &&, env subst)
81
+ are preserved because the command body is handed to sh untouched
82
+
83
+ - **`publint`, `mutation-report`, `supply-chain` (socket probe) now spawn
84
+ their target binaries directly** instead of `pnpm exec`. Same direct-spawn
85
+ pattern as 0.7.2 lint/coverage/e2e/convex-build. publint and mutation-report
86
+ retain `pnpm dlx` fallbacks for explicit opt-in (`--dlx <spec>`).
87
+
88
+ ### Internal
89
+
90
+ - `PnpmFiltersResult.argv` field renamed to `invocations: {label, cwd, command}[]`.
91
+ CLI consumers (`cli.ts`) only read `status`, which is unchanged. Library
92
+ consumers parsing the report shape are affected — hence the minor bump.
93
+
94
+ ### Benchmarks (against geenius-logger, 4 implemented variants)
95
+
96
+ pnpm build (sequential, --workspace-concurrency=1):
97
+ 0.7.2 → ~12s (~3s pnpm bootstrap + ~9s real build)
98
+ 0.8.0 → ~8.8s (~0s pnpm bootstrap + ~8.8s real build)
99
+
100
+ pnpm clean (parallel):
101
+ 0.7.2 → ~1.5s (pnpm bootstrap + rm -rf dist × 3)
102
+ 0.8.0 → ~0.8s (sh -c rm -rf dist × 3)
103
+
104
+ Under heavy concurrent agent workloads (10-20× parallel), the savings
105
+ compound — pnpm bootstrap was previously the dominant cost.
106
+
107
+ ## [0.7.2] — 2026-05-17
108
+
109
+ ### Performance
110
+
111
+ - **`lint`, `coverage`, `e2e`, `convex-build` now spawn local binaries
112
+ directly** instead of routing through `pnpm exec`. Saves the
113
+ ~100-300ms pnpm bootstrap per spawn — critical when 10-20 agents
114
+ invoke a `geenius-release` subcommand concurrently. New helper
115
+ `src/lib/resolve-bin.ts` walks ancestor `node_modules/.bin` (cached
116
+ per-process); env-PATH augmentation lets child processes find sibling
117
+ bins (tsup → esbuild, vitest → workers) without further hops.
118
+
119
+ ### Changed
120
+
121
+ - Removed all in-tree references to `@geenius-agents`. The release
122
+ toolkit ships as a self-contained CLI/library; downstream report
123
+ consumers (CI integrations, dashboards) are not named in source or
124
+ docs.
125
+
126
+ ## [0.7.1] — 2026-05-17
127
+
128
+ ### Added
129
+
130
+ - **`bundle-budgets`** — gzip-check `<packageDir>/dist/{index.js,index.css}` against
131
+ each variant's `bundleBudget` declared in `variants.json`. Replaces
132
+ `scripts/check-bundle-budgets.mjs` (surfaced from geenius-perf). 8 packages
133
+ declare `bundleBudget` (perf, agent, ai-magic, devtools, errors, onboarding,
134
+ ui, tools-legacy); this command absorbs the pattern for all of them.
135
+ Flags: `--assets`, `--include-unimplemented`, `--optional`.
136
+
137
+ ## [0.7.0] — 2026-05-17
138
+
139
+ ### Added
140
+
141
+ Nine new commands that absorb every standalone `scripts/*.mjs` used in 3 or more
142
+ geenius packages. Designed to clear the per-package script tail so package
143
+ `scripts/` directories can hold only genuinely package-unique logic. See
144
+ `standardization-plan.md` for the full migration map.
145
+
146
+ - **`lint`** — canonical biome runner. Collapses `run-lint.mjs` (9 pkgs),
147
+ `lint-apps.mjs` (4), `lint-scope.mjs` (3), `biome-scope.mjs` (5). Flags:
148
+ `--scope <package|apps|all>`, `--apps`, `--command`, `--fix`, `--print`.
149
+
150
+ - **`coverage`** — canonical `vitest run --coverage` runner. Collapses
151
+ `run-coverage.mjs` (5). Cleans coverage dirs, runs root pass excluding
152
+ separate-coverage packages, then runs per-package passes. Flags:
153
+ `--separate-frameworks`, `--separate-package-dirs`, `--no-clean`, `--strict`.
154
+
155
+ - **`e2e`** — Playwright runner with ephemeral port reservation and
156
+ variant-derived `--project` filters. Collapses `e2e-runner.mjs` (5) and
157
+ `playwright-projects.mjs` (2). Flags: `--projects`, `--all-browsers`,
158
+ `--browser`, `--env-prefix`, `--print`.
159
+
160
+ - **`vitest-browser-prepare`** — exports `vitestBrowserPrepareRetry()` for
161
+ vitest configs; the CLI prints the injected script. Collapses
162
+ `vitest-browser-prepare-retry.ts` (4 pkgs).
163
+
164
+ - **`patch-dts`** — post-build dist patcher. Collapses `patch-dts-imports.mjs`
165
+ (4), `patch-solid-web-import.mjs` (2). Flags: `--rewrite <from=to>`
166
+ (repeatable, .d.ts only), `--solid`, `--solid-jsx`, `--dir`, `--files`.
167
+
168
+ - **`db-migrations`** — runs migration tests for every `db-provider` variant
169
+ with `tests.migrations: true`. Collapses `db-migrations-check.mjs` (4).
170
+
171
+ - **`sanitize-dist`** — strips tsup source-path comments, sourcemap URLs, and
172
+ optionally the Solid JSX runtime import from `dist/`. Collapses
173
+ `sanitize-dist-comments.mjs` (3) and `sanitize-dist.mjs` (2). Flags:
174
+ `--no-comments`, `--maps`, `--fix-solid-jsx-runtime`, `--dir`.
175
+
176
+ - **`convex-codegen`** — generates `_generated/{server,api,dataModel}` shims
177
+ for Convex variants. Promotes the bin previously shipped from
178
+ `geenius-db`'s convex sub-package. Flags: `--src`, `--check`, `--clean`.
179
+
180
+ - **`convex-build`** — Convex sub-package build = `convex-codegen` + `tsup`.
181
+ One implementation for the 16 packages carrying `convex.config.ts`. Flags:
182
+ `--src`, `--no-codegen`, `--no-build`, `--clean`, `--builder <tsup|tsc>`.
183
+
184
+ ## [0.6.1] — 2026-05-17
185
+
186
+ ### Fixed
187
+
188
+ - **`pnpm-filters` CLI now exposes `--requires` and `--mode`**. The 0.6.0 release wired both options into the `runPnpmFilters` library API but forgot to register them on the CLI definition, so `geenius-release pnpm-filters … --mode shared-then-parallel` rejected the flag. Both flags now work as documented.
189
+ - **`storybook --runner test-runner` no longer passes the invalid `--static-dir` flag** to `@storybook/test-runner`. The toolkit now spins up an ephemeral static file server on a free port, points the runner at it via `--url http://127.0.0.1:<port>`, and tears the server down after the run completes.
190
+
191
+ ## [0.6.0] — 2026-05-17
192
+
193
+ ### Added
194
+
195
+ - **`variants check`** subcommand — verifies every required variant has an on-disk `packageDir`. With `--require-all`, every variant is required regardless of `required:false`. Replaces ad-hoc `variants-check.mjs` shims.
196
+ - **`pnpm-filters --requires <names>`** — verify a comma-separated list of binaries is on PATH before fanning out. Fails fast with a clear error instead of a confusing per-variant spawn failure.
197
+ - **`pnpm-filters --mode shared-then-parallel`** — run a single shared package first (e.g. `packages/shared`) and then fan the rest out in parallel. Replaces hand-written shared-first wrappers that called pnpm twice.
198
+ - **`mutation-report --check-config-only`** — validate Stryker config without running mutations. For CI gates that want to ensure config drift is caught early.
199
+ - **`mutation-report --dlx <spec>`** — fall back to `pnpm dlx <spec>` when Stryker isn't installed locally. Lets packages opt into mutation testing without committing the dependency.
200
+ - **`mutation-report --markdown <path> --json <path> --report-json <path>`** — emit derived reports alongside the raw Stryker output, with fallback score computation when Stryker's summary fails.
201
+ - **`attw --safe-pack-dir <path>`** — reuse a stable dir (relative to `packageRoot`) instead of mkdtemp for the tarball. Useful when CI caches need a deterministic path.
202
+ - **`diff-coverage --min-ci <pct>` and `--min-local <pct>`** — CI-conditional thresholds. Common pattern: 0 locally, strict in CI, so contributors aren't blocked but coverage regressions still fail the pipeline.
203
+ - **`storybook --runner test-runner|vitest|static-smoke`** — pick between `@storybook/test-runner`, Vitest browser-mode runner, or the original Playwright static smoke. Replaces 3 categories of per-package storybook smoke scripts.
204
+ - **`rewrite-imports --preset solid-web`** — built-in preset that rewrites `solid-js/web` to `solid-js/web/dist/web.js` so Node ESM consumers can resolve it without subpath redirects. Replaces per-Solid-package rewrite shims.
205
+
206
+ ### Changed
207
+
208
+ - **`variants-rich`** now understands `packagePath` as a fallback for `packageDir`, plus top-level `workspacePackages` arrays. Lets packages that follow either convention (admin's bare-name `react`, or ai-workflow's separate `workspacePackages`) consume the toolkit without rewriting their `variants.json`.
209
+
210
+ ## [0.5.0] — 2026-05-17
211
+
212
+ ### Added
213
+
214
+ - **`run-scripts <s1> <s2> …`** + `runScripts` API — run multiple top-level `package.json` scripts sequentially in the package root, with PATH augmented to `node_modules/.bin` and `npm_package_*` env vars set. Stops on first failure (or `--continue-on-failure`). Replaces local `_run-root-scripts.mjs` shims used to chain build/test/exports/dist-contract.
215
+ - **`type-check`** + `runTypeCheck` API — per-variant runner with a `type-check → lint → tsc --noEmit` fallback chain. Augments PATH with the variant's and root's `node_modules/.bin`. Honors `--shared-first`, `--continue-on-failure`, `--exclude-out-of-scope`. Replaces `scripts/type-check-packages.mjs`.
216
+ - **`size-limit-config`** + `runSizeLimitConfig` API — emit size-limit entries to stdout, derived from `variants.json` `budget.gzip` and the root manifest's `exports` map. Enforces that every exported package has a `budget.gzip`. Replaces ~5 copies of per-package `size-limit-config.mjs`.
217
+ - **`pack-contract`** + `runPackContract` API — generic harness: `pnpm pack --json` into a tmp dir, expose path via `PACK_CONTRACT_JSON` env, run a consumer-supplied `vitest --config <path>`. Replaces local `pack-contract.mjs` shims.
218
+
219
+ ### Changed
220
+
221
+ - **`pnpm-filters` gains sequential mode**. New flags: `--sequential`, `--shared-first <packageDir>`, `--heartbeat-ms <ms>`, `--kind-order <tiers>` (pipe-separated tiers, comma-separated kinds). Sequential mode walks variants one at a time, runs `packages/shared` first when requested, skips packages that don't declare the script, emits a heartbeat line every N ms so CI doesn't kill a quiet job. The default parallel mode is unchanged. Replaces 43 copies of `_pnpm-filters.mjs` and the package-specific shared-first variants in adapters/admin/agent/ai.
222
+ - **`runPnpmFilters` is now `async`**. The signature returns `Promise<PnpmFiltersResult>` because the sequential path uses `spawn` to run the heartbeat alongside the child process. Parallel callers must `await` the result (no behavior change otherwise). The CLI was already async, so no user-facing change.
223
+ - **`coverage-report` accepts per-subpackage thresholds**. New flags: `--threshold-file <path>`, `--output <path>` (Markdown), `--json <path>` (structured), `--fail-on-gaps`. The threshold file shape is `{ subpackages: { <name>: { thresholds: { lines, statements, branches, functions }, required?, kind? } } }`. The toolkit walks per-subpackage `coverage-summary.json` files under `packages/<name>/coverage/`, computes pass/fail per metric, and writes Markdown + JSON reports. Replaces the 36-script category for packages whose call sites use these flags.
224
+ - **`storybook` gains variant-driven discovery + shape check**. New flags: `--from-variants` (read app list from `variants.json` instead of auto-globbing `apps/storybook-*`), `--variants-scope <all|published>`, `--check-shape <jsonOrPath>` (asserts `requiredFiles`/`forbiddenFiles`/`requiredTitles` per app). Replaces variant-filtered `storybook-build.mjs` and `storybook-vitest-runner.mjs` shims, plus per-package `storybook-app-smoke.mjs`.
225
+
226
+ ### Migration
227
+
228
+ `runPnpmFilters` is now async. If you import it as a library, `await` the call. CLI users see no change.
229
+
230
+ ## [0.4.0] — 2026-05-17
231
+
232
+ ### Fixed
233
+
234
+ - **`smoke-packed` no longer swallows the npm install error.** The `--silent` flag was suppressing the stderr stream the `link:`/`workspace:` fallback regex depended on, producing "npm install exited 1" with empty `output` and forcing every Geenius package to ship its own `smoke-packed-imports.mjs` workaround (~36 copies, ~286 LOC each). The install now runs without `--silent`, falls back to `pnpm add` unconditionally on exit≠0, and reports the combined stderr from every attempt.
235
+
236
+ ### Added
237
+
238
+ - **`publint` source-time `link:` tolerance.** When publint reports diagnostics of the form `The "X" dependency references "link:..."` for `X` declared in the manifest and matching `publint.sourceLinkScope` (default `^@geenius/`), the toolkit treats the run as passed. The semver rewrite that converts these to ranges still happens at publish time. Config: `publint.allowSourceTimeLinks` (default `true`), `publint.sourceLinkScope`. Replaces ~25 per-package `lint-pub.mjs` / `publint-package.mjs` wrappers.
239
+ - **Gauntlet sibling-dist freshness pre-check.** Before running the first step, the gauntlet walks every `link:` `@geenius/*` dep, verifies its `dist/index.js` + `dist/index.d.ts` are newer than its `src/`, and either fails (`siblingDistFreshness: "check"`, default) or auto-builds (`siblingDistFreshness: "build"`). Eliminates the recurring TS7016 "cannot resolve declarations" failures inside nested gauntlet runs.
240
+ - **`geenius-release variants [list|missing|published-subpaths|ui|db|storybook-apps]`** + a programmatic `loadRichVariants` / `packageVariants` / `uiVariants` / `storybookApps` / `publishedSubpaths` API. Reads `variants.json`, honors `OMEGA_INCLUDE_OUT_OF_SCOPE`, returns derived `packagePath` / `exists` / `subpaths` fields. Replaces 43 copies of `scripts/_variants.mjs`.
241
+ - **`geenius-release pnpm-filters <task> [...passthrough]`** + `runPnpmFilters` programmatic API. Builds `pnpm -r --filter ./packages/<X>` invocations from the active variant matrix. Replaces 43 copies of `scripts/_pnpm-filters.mjs`.
242
+ - **`geenius-release storybook --static-smoke <replace|after|only>`** runs the toolkit's built-in Playwright + http-server smoke against `apps/*/storybook-static`. Visits every indexed story under headless Chromium, asserts `#storybook-root` is non-empty, fails on page errors. `@playwright/test` is loaded lazily; if the consuming package doesn't have it the step reports a clear missing-peer error. Replaces ~30 copies of `storybook-runner.mjs` / `storybook-test-runner.mjs` / `test-storybook-static.mjs` that agents had to keep reinventing after Storybook's Vitest browser addon kept hanging.
243
+
244
+ ## [0.3.4] — 2026-05-16
245
+
246
+ ### Added
247
+
248
+ - `rewrite-imports` now supports `deriveFromExports: true` (config + `--derive-from-exports` CLI flag). When set, the toolkit reads the root manifest's `exports` map, walks `packages/<name>/package.json` for each referenced variant, and generates one literal rule per private→public pair (e.g. `@geenius/i18n-react` → `@geenius/i18n/react`). Replaces hand-rolled scripts like i18n's `patch-dts-imports.mjs` (~129 LOC). Derived rules are appended after explicit `rules`.
249
+
250
+ ## [0.3.3] — 2026-05-16
251
+
252
+ ### Added
253
+
254
+ - `rewrite-imports` rules now support a `literal: true` flag — when set, `replaceWith` is treated as literal text instead of a path-relative-to-packageRoot. Useful for JSDoc / comment cleanup ("internal-name → public-name") where there's no file to resolve against.
255
+ - `rewrite-imports` rules now support a `quoted: true` flag — when set, only quoted occurrences are matched (both `"<match>"` and `'<match>'`). Use this for specifier rewrites that must not touch identical strings in JSDoc / comments.
256
+ - `rewriteImports.extensions` config (and `extensions` option on the programmatic API) — list of file extensions to rewrite. Defaults to `[".js", ".d.ts"]`. Packages emitting `.cjs`/`.cts`/`.mjs` can now opt in.
257
+
258
+ ## [0.3.2] — 2026-05-16
259
+
260
+ ### Fixed
261
+
262
+ - **`loadConfig` now walks up from a subdirectory** to find the package root before reading `release-toolkit.config.json`. Previously, when a CLI command was invoked from a variant subdirectory (e.g. a per-variant build script chaining `tsup && geenius-release rewrite-imports packages/<variant>`), the config was silently missed because `loadConfig` joined `release-toolkit.config.json` onto the raw cwd. Affected every command that reads config — most visibly `rewrite-imports`, where the resulting `no rules configured` skip silently let private specifiers leak into dist. The CLI now calls `resolvePaths(startCwd).packageRoot` first.
263
+
264
+ ## [0.3.1] — 2026-05-16
265
+
266
+ ### Added
267
+
268
+ - `rewrite-imports <variant-dir>` — post-build codemod that rewrites private subpath imports (e.g. `@geenius/<pkg>/shared/react`) in a variant's built `dist/` into relative dist paths, so packed tarballs don't need to expose internal `./shared` exports. Replaces ~36 copies of `rewrite-private-imports.mjs` (≈ 2,800 LOC). Token-aware rules (`${packageName}`, `${framework}`, `${variant}`) configured under `rewriteImports` in `release-toolkit.config.json`, or supplied inline via repeatable `--rule <match>=<replaceWith>`. Auto-detects framework from variant basename (`solidjs*` → `solidjs`, else `react`); overridable via `--framework` or `rewriteImports.frameworkDetect` regex map.
269
+
270
+ ### Fixed
271
+
272
+ - `manifest-contract`: replace hand-rolled glob with picomatch so `files` patterns like `packages/*/dist/**/*` correctly cover exports/main/types targets.
273
+ - `size-check`: default to optional (mirrors `mutation-report`); CLI flag flipped from `--optional` to `--required`. Packages without `size-limit` configured no longer break the gauntlet.
274
+ - `smoke-packed`: when `npm install` of the packed tarball fails due to unresolved `link:`/`workspace:` deps, retry with `pnpm add` so monorepo packages with workspace siblings can be smoke-tested end-to-end.
275
+
276
+ ## [0.3.0] — 2026-05-16
277
+
278
+ ### Added
279
+
280
+ - **4 new subcommands**, taking the surface from 11 → 15 and completing every legacy-script category:
281
+ - `diff-coverage` — changed-line coverage diff vs a git base ref. Parses `git diff --unified=0 <base>...HEAD`, walks istanbul `coverage-final.json`, enforces `--min` (default 80%). Replaces 22 copies of `diff-coverage.mjs`.
282
+ - `manifest-contract` — verify `package.json:main/types/module/exports/bin` resolve on disk, `bin` entries are executable + have shebangs, and `files` patterns cover every export target. Absorbs the `test -f dist/index.js` inline checks scattered across the ecosystem (e.g. tools/devtools' `test:dist-contract`).
283
+ - `storybook` — build + test-run every Storybook app declared (or auto-discovered under `apps/storybook-*`). Replaces ~28 scripts across 5 filename variations (`storybook-runner.mjs`, `storybook-test-runner.mjs`, `test-storybook-static.mjs`, `storybook-build.mjs`, `storybook-apps.mjs`).
284
+ - `perf-smoke` — enforce perf budgets against `.eval/perf/results.json`. Supports both array `[{ metric, value }]` and object `{ metric: value }` result formats; reads budgets from `perf-budgets.json` if no inline config. Replaces 7 copies.
285
+ - Each new command exported from the programmatic API (`runDiffCoverage`, `runManifestContract`, `runStorybook`, `runPerfSmoke`).
286
+ - Gauntlet integration: all 4 new commands are recognized internal steps.
287
+
288
+ ### Cumulative absorption
289
+
290
+ The toolkit now replaces approximately **260+ legacy `scripts/*.mjs` files** across the ecosystem (≈ 49,000 LOC of duplication). Every category of release-gate script identified in the original audit has a corresponding canonical subcommand.
291
+
292
+ ## [0.2.0] — 2026-05-16
293
+
294
+ ### Added
295
+
296
+ - **6 new subcommands** absorbing ~80 more legacy `scripts/*.mjs` files across the ecosystem:
297
+ - `publint` — run publint against the packed tarball. Replaces 4 filename variations (~17 copies).
298
+ - `attw` — run `@arethetypeswrong/cli` against the packed tarball. Replaces 3 filename variations (~13 copies).
299
+ - `size-check` — size-limit driver. Replaces 13 copies.
300
+ - `coverage-report` — aggregate `coverage-summary.json` and enforce per-metric thresholds. Replaces 36 copies. Reads `coverage-thresholds.json` if present.
301
+ - `mutation-report` — Stryker driver. Optional by default. Replaces 36 copies.
302
+ - `a11y-report` — aggregate axe-core results from `.eval/a11y/results.json` and enforce a severity threshold. Replaces 28 copies.
303
+ - **Programmatic API** for every new subcommand: `runPublint`, `runAttw`, `runSizeCheck`, `runCoverageReport`, `runMutationReport`, `runA11yReport`.
304
+ - **Gauntlet integration**: every new subcommand is a recognised internal step in `geenius-release gauntlet`.
305
+ - **`$schema` allowed in `release-toolkit.config.json`** so editors get JSON-schema autocomplete (no runtime effect).
306
+ - **Repository infrastructure** to match the rest of the geenius ecosystem:
307
+ - `LICENSE` file (FSL-1.1-Apache-2.0)
308
+ - `CODE_OF_CONDUCT.md`, `CONTRIBUTING.md`, `SECURITY.md`, `SUPPORT.md`
309
+ - `.github/CODEOWNERS`, `dependabot.yml`, `PULL_REQUEST_TEMPLATE.md`, issue templates
310
+ - `.github/workflows/ci.yml` (PR + nightly with `osv-scanner` install + Socket strict mode)
311
+ - `.github/workflows/release.yml` (changesets-driven publish)
312
+ - `.changeset/config.json`
313
+ - `.nvmrc`
314
+ - `@changesets/cli` added to devDependencies; `publint` and `@arethetypeswrong/cli` added so the toolkit's own gauntlet can run them.
315
+
316
+ ### Changed
317
+
318
+ - `tsup.config.ts` scopes `dts` generation to the `index` entry only — `cli.ts` is a script, not a typed-library entry, so an empty `.d.ts` is no longer emitted.
319
+ - Package exports now include `default` alongside `import` for stricter ESM-only resolver tolerance.
320
+
321
+ ### Known issues
322
+
323
+ - **`attw` crashes with `Cannot read properties of undefined (reading 'filename')`** when run against the toolkit's own packed tarball under `@arethetypeswrong/cli@0.18.2`. The same attw version works correctly on every other geenius package; the toolkit's own bootstrap dogfood gauntlet excludes `attw` until the upstream issue is resolved. The toolkit itself is unaffected — running `geenius-release attw` against consumer packages works as designed.
324
+
325
+ ## [0.1.0] — 2026-05-15
326
+
327
+ Initial greenfield release. See the git history of this file for the original v0.1 entry.
328
+
329
+ ### Added
330
+
331
+ - CLI `geenius-release` with subcommands `supply-chain`, `license`, `sbom`, `smoke-packed`, `gauntlet`.
332
+ - Programmatic API exports for every subcommand.
333
+ - `release-toolkit.config.json` schema (Zod) with sensible defaults.
334
+ - Env overrides (`GEENIUS_SUPPLY_CHAIN_<SCANNER>=off|optional|required`, `GEENIUS_RELEASE_STRICTNESS`, `SOCKET_API_TOKEN`).
335
+ - Stable exit codes (0–4) and stable JSON report shape.
package/LICENSE ADDED
@@ -0,0 +1,88 @@
1
+ Functional Source License, Version 1.1, Apache 2.0 Future License
2
+
3
+ Abbreviation
4
+
5
+ FSL-1.1-Apache-2.0
6
+
7
+ Notice
8
+
9
+ Copyright 2026 Mehdi Nabhani
10
+
11
+ License
12
+
13
+ Terms and Conditions
14
+
15
+ Licensor ("We") provides the Software described in the Notice, and reserves
16
+ all rights in it other than those expressly granted in this License.
17
+
18
+ Permitted Purpose means any purpose other than a Competing Use. A Competing
19
+ Use means making the Software available to third parties as a hosted or
20
+ managed service, where the service provides users with access to any
21
+ substantial set of the features or functionality of the Software. Permitted
22
+ Purpose expressly includes any internal use by employees and contractors of
23
+ your business, and use by your customers that is limited to interactions
24
+ with your products and services.
25
+
26
+ License Grant
27
+
28
+ Subject to your compliance with this License, We grant you a non-exclusive,
29
+ royalty-free, worldwide, non-sublicensable, non-transferable license to
30
+ use, copy, distribute, make available, and prepare derivative works of the
31
+ Software, in each case subject to the limitations and conditions below.
32
+
33
+ Limitations
34
+
35
+ You may not make any use of the Software that competes with Our business.
36
+ That includes (without limitation) offering the Software as a hosted or
37
+ managed service to third parties.
38
+
39
+ You may not move, change, disable, or circumvent any license key functionality
40
+ in the Software, and you may not remove or obscure any functionality in the
41
+ Software that is protected by a license key.
42
+
43
+ Patents
44
+
45
+ To the extent your use for a Permitted Purpose would necessarily infringe
46
+ Our patents, the license grant above includes a license under Our patents.
47
+ If you make a claim against any party that the Software infringes or
48
+ contributes to the infringement of any patent, then your patent license to
49
+ the Software ends immediately.
50
+
51
+ Redistribution
52
+
53
+ The Terms and Conditions of this License apply to any copy, modification,
54
+ or derivative work of the Software that you distribute. You must include
55
+ a copy of this License with every such copy, and you must retain all
56
+ copyright, trademark, and attribution notices.
57
+
58
+ Disclaimer
59
+
60
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND,
61
+ INCLUDING WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR
62
+ A PARTICULAR PURPOSE, NON-INFRINGEMENT, OR THAT THE SOFTWARE WILL BE
63
+ ERROR-FREE.
64
+
65
+ IN NO EVENT WILL WE BE LIABLE TO YOU FOR ANY DAMAGES ARISING OUT OF OR
66
+ RELATED TO THIS LICENSE, INCLUDING DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
67
+ CONSEQUENTIAL, OR PUNITIVE DAMAGES, EVEN IF WE HAVE BEEN ADVISED OF THE
68
+ POSSIBILITY OF SUCH DAMAGES.
69
+
70
+ Future License
71
+
72
+ On the second anniversary of the date the Software is first distributed
73
+ under this License, the Software will automatically also be made available
74
+ under the Apache License, Version 2.0 (the "Future License"). You may, at
75
+ your option, continue to use the Software under the terms of this License,
76
+ or you may use the Software under the terms of the Future License.
77
+
78
+ Your compliance with the Future License is a condition of your receiving
79
+ the Software under that license.
80
+
81
+ The Future License text is available at:
82
+ https://www.apache.org/licenses/LICENSE-2.0
83
+
84
+ Trademarks
85
+
86
+ Except for the limited use required to comply with the Notice section
87
+ above or as required by the redistribution terms, this License does not
88
+ grant you any right in any trademark, service mark, or logo of Ours.
package/README.md ADDED
@@ -0,0 +1,104 @@
1
+ # @geenius/release-toolkit
2
+
3
+ > Canonical release toolkit for every Geenius package and boilerplate. One CLI (`geenius-release`) replaces the per-package supply-chain / license / SBOM / smoke-packed / gauntlet scripts that previously lived as 26–36 hand-copied duplicates.
4
+
5
+ **Dev-only.** Add to `devDependencies`; never appears in your runtime bundle.
6
+
7
+ ```bash
8
+ pnpm add -D @geenius/release-toolkit
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ Wire the canonical scripts into your `package.json`:
14
+
15
+ ```jsonc
16
+ {
17
+ "scripts": {
18
+ "audit:supply-chain": "geenius-release supply-chain",
19
+ "audit:license": "geenius-release license",
20
+ "audit:sbom": "geenius-release sbom",
21
+ "test:smoke-packed": "geenius-release smoke-packed",
22
+ "test:gauntlet": "geenius-release gauntlet"
23
+ }
24
+ }
25
+ ```
26
+
27
+ No config file required — the toolkit ships ecosystem-sensible defaults. Add `release-toolkit.config.json` next to `package.json` to override.
28
+
29
+ ## Subcommands (v0.1)
30
+
31
+ | Subcommand | Replaces | Description |
32
+ | --- | --- | --- |
33
+ | `supply-chain` | 26 per-package scripts | pnpm audit + osv-scanner + Socket + license, all required/optional configurable |
34
+ | `license` | 36 copies of `license-check.mjs` | Forbidden-license scan over installed deps |
35
+ | `sbom` | 36 copies of `sbom.mjs` | CycloneDX 1.5 JSON SBOM (optional SPDX via `syft`) |
36
+ | `smoke-packed` | 36 copies of `smoke-packed-imports.mjs` | Pack, install, dynamic-import every subpath in `package.json:exports` |
37
+ | `gauntlet` | The `&&`-chained `pnpm test:gauntlet` macro | Compose the configured step sequence into one structured report |
38
+
39
+ v0.2 adds `coverage-report`, `diff-coverage`, `mutation-report`, `a11y-report`, `size-check`. v0.3 adds `storybook`, `publint`, `attw`, `perf-smoke`.
40
+
41
+ ## Opting out of Socket
42
+
43
+ Socket requires a free account. To opt out:
44
+
45
+ ```jsonc
46
+ {
47
+ "supplyChain": {
48
+ "scanners": { "socket": { "required": false } }
49
+ }
50
+ }
51
+ ```
52
+
53
+ `required: false` is the default for every boilerplate. Internal `@geenius/*` packages opt-in to strict mode in CI via `SOCKET_API_TOKEN`. Env override for one-off CI runs:
54
+
55
+ ```bash
56
+ GEENIUS_SUPPLY_CHAIN_SOCKET=off geenius-release supply-chain
57
+ ```
58
+
59
+ ## Configuration reference
60
+
61
+ See [`.docs/DOCS/PACKAGES/RELEASE_TOOLKIT.md`](../../.docs/DOCS/PACKAGES/RELEASE_TOOLKIT.md) for the full config schema and examples, and [`.docs/PRDS/packages/PACKAGE_RELEASE_TOOLKIT_PRD.md`](../../.docs/PRDS/packages/PACKAGE_RELEASE_TOOLKIT_PRD.md) for the design rationale.
62
+
63
+ ## Exit codes
64
+
65
+ | Code | Meaning |
66
+ | --- | --- |
67
+ | `0` | Required steps passed (optional steps may have skipped) |
68
+ | `1` | At least one required step failed |
69
+ | `2` | Configuration error |
70
+ | `3` | Environment error (missing pnpm, missing lockfile) |
71
+ | `4` | Internal toolkit bug |
72
+
73
+ Stable across versions. CI integrations can rely on them.
74
+
75
+ ## Optional git hooks
76
+
77
+ The toolkit ships a non-blocking pre-push hook template at `templates/husky/pre-push`. It runs `pnpm run audit:supply-chain` before each push and reports findings without blocking the push (remove the trailing `|| exit 0` in the script to make findings blocking).
78
+
79
+ Install per-repo:
80
+
81
+ ```bash
82
+ cp node_modules/@geenius/release-toolkit/templates/husky/pre-push .husky/pre-push
83
+ chmod +x .husky/pre-push
84
+ ```
85
+
86
+ The hook is not auto-installed by adding the toolkit as a dependency — adoption is opt-in.
87
+
88
+ ## Reports
89
+
90
+ Every subcommand writes a JSON report at `.eval/release-toolkit/<command>.json`. The shape is documented in [`src/types.ts`](./src/types.ts) and is consumed by CI integrations and downstream report aggregators.
91
+
92
+ ## Development
93
+
94
+ ```bash
95
+ pnpm install
96
+ pnpm build
97
+ pnpm test
98
+ pnpm lint
99
+ pnpm exec geenius-release gauntlet # dogfood
100
+ ```
101
+
102
+ ## License
103
+
104
+ FSL-1.1-Apache-2.0
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ // Entry shim. The real CLI lives in ./dist/cli.js; this file exists so
3
+ // `bin` resolution lands on a stable, sourcemapped path without exposing
4
+ // the dist layout to consumers.
5
+ import("../dist/cli.js");