@hublo/sentinel 1.2.0-alpha.9 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -133,16 +133,31 @@ The per-tool knowledge (eslint → `eslint.config.js`, tsc → `tsconfig`, …)
133
133
 
134
134
  ## Requirements & installing
135
135
 
136
- **Registry: public npm**, under `@hublo`. We started on **GitHub Packages (private)** and moved off it: it authenticates every consumer, including a one-off `pnpm dlx`, which is incompatible with the zero-setup adoption above. Public npm needs no consumer auth, so a module adopts sentinel without any `.npmrc` or token. Releases go out through the repo's `publish` workflow, never from a laptop; a prerelease is published under its prerelease dist-tag (`alpha`) and a stable one under `latest`.
136
+ **Registry: public npm**, under `@hublo`. We started on **GitHub Packages (private)** and moved off it: it authenticates every consumer, including a one-off run, which is incompatible with the zero-setup adoption above. Public npm needs no consumer auth, so a module adopts sentinel without any `.npmrc` or token. Releases go out through the repo's `publish` workflow, never from a laptop; a prerelease is published under its prerelease dist-tag (`alpha`) and a stable one under `latest`.
137
137
 
138
138
  **Node.** sentinel needs **Node >= 20.12** (its coloured output uses `util.styleText`, added in 20.12). It fails fast with a clear message on an older runtime rather than crashing. If a project runs on an older Node (e.g. a legacy app on Node 10), run sentinel with a modern Node via `fnm`/`nvm`; you do not need to change the project's own Node.
139
139
 
140
140
  **Try it without installing.** A one-off run needs no auth and touches nothing:
141
141
 
142
142
  ```bash
143
- pnpm dlx @hublo/sentinel@<exact-version> --inspect --typescript --module <name>
143
+ npx --yes @hublo/sentinel@<exact-version> --inspect --typescript --module <name>
144
144
  ```
145
145
 
146
+ **Why `npx` and not `pnpm dlx`, in a pnpm monorepo.** Because `pnpm dlx` no longer works for this,
147
+ and no flag fixes it. pnpm's `strictDepBuilds` defaults to **true**, so adding a package whose build
148
+ scripts have not been approved is a FATAL error rather than the warning it was through pnpm 10
149
+ ([settings/build](https://pnpm.io/settings/build)). sentinel pulls `esbuild` and `nx`, so the
150
+ install aborts _before sentinel runs at all_: exit 1, nothing on stdout.
151
+
152
+ The usual remedy, `allowBuilds` in `pnpm-workspace.yaml`, cannot reach it either: `dlx` runs in a
153
+ throwaway project outside the workspace, so the workspace's approvals do not apply. `--allow-build`,
154
+ `--config.dangerouslyAllowAllBuilds` and `--config.strictDepBuilds=false` were each measured and
155
+ each still exits 1.
156
+
157
+ `npx` fetches the same published package and runs no dependency build scripts, which is what a
158
+ throwaway run wants. Once a module has adopted, nothing is fetched any more: the scripts call the
159
+ `sentinel` binary from the module's own `devDependencies`.
160
+
146
161
  **Installing a pre-release (`minimumReleaseAge`).** The monorepo enforces a 3-day `minimumReleaseAge` supply-chain gate (a freshly published version cannot be installed until it has aged 3 days). A brand-new `alpha` therefore cannot be added yet, so while testing pre-releases you either exclude the package (`pnpm-workspace.yaml` → `minimumReleaseAgeExclude`) or install with `--config.minimumReleaseAge=0`. This is a deliberate protection, not a bug: **always pin the exact version** (`@hublo/sentinel@0.1.0-alpha.9`) rather than `@latest`, so a run is reproducible and the gate stays meaningful.
147
162
 
148
163
  ## Docs & cheat sheets
@@ -4,3 +4,4 @@ import '@vitejs/plugin-react';
4
4
  import 'nitro/vite';
5
5
  import 'vite-plugin-svgr';
6
6
  import 'vite';
7
+ import 'vitest/config';
@@ -9,6 +9,7 @@ import {
9
9
  WORKSPACE_ROOT_MARKER,
10
10
  availableTargets,
11
11
  buildConfigFile,
12
+ correctingSignal,
12
13
  declaredPresetFor,
13
14
  describeFramework,
14
15
  dispatch,
@@ -22,7 +23,7 @@ import {
22
23
  registerAdapters,
23
24
  resolve,
24
25
  resolveBin
25
- } from "../chunk-6RH3LZQZ.js";
26
+ } from "../chunk-676GBPMS.js";
26
27
 
27
28
  // bin/sentinel.ts
28
29
  import { program } from "commander";
@@ -114,7 +115,7 @@ function resolveContext(cwd2, opts2) {
114
115
  );
115
116
  }
116
117
 
117
- // src/roles/build/scope.ts
118
+ // src/roles/build/declined.ts
118
119
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
119
120
  import { join as join3 } from "path";
120
121
  var DEPRECATED_NX_BUILDER = "@nx/webpack:webpack";
@@ -128,7 +129,7 @@ function buildsWithDeprecatedExecutor(cwd2) {
128
129
  return false;
129
130
  }
130
131
  }
131
- function explainBuildScope(cwd2) {
132
+ function explainDecline(cwd2) {
132
133
  if (buildConfigFile(cwd2) !== void 0) {
133
134
  return ` This module HAS a Vite config, so detection is the likely problem: the build toolchain is declared at the workspace root, which makes a front app detect as "node". Pass --preset to say what it is.`;
134
135
  }
@@ -176,7 +177,7 @@ async function runInit(ctx) {
176
177
  } catch (error) {
177
178
  if (error instanceof PresetUnsupportedError) {
178
179
  if (ctx.targetsExplicit) {
179
- const hint = type === "build" ? explainBuildScope(module.root) : ` Pass --preset if it was detected wrongly (hoisted dependencies make detection fall back to "node").`;
180
+ const hint = type === "build" ? explainDecline(module.root) : ` Pass --preset if it was detected wrongly (hoisted dependencies make detection fall back to "node").`;
180
181
  process.stderr.write(
181
182
  `
182
183
  sentinel (${type}): this module's preset is "${error.preset}", and --${type} has no adapter for it.${hint}
@@ -235,6 +236,7 @@ async function analyse(params) {
235
236
  ) + "\n"
236
237
  );
237
238
  }
239
+ preset2 = correctingSignal(preset2, module.root)?.preset ?? preset2;
238
240
  }
239
241
  for (const target of params.targets) {
240
242
  let adapter;
@@ -655,7 +657,10 @@ program.name("sentinel").description("One CLI that guards code health: presets,
655
657
  " sentinel --run --json # from root \u2192 all types, machine output",
656
658
  " sentinel --run --ci # from root \u2192 affected only",
657
659
  " sentinel --inspect --typescript # from root \u2192 adoption + what is deferred",
658
- " sentinel --init --preset react # adopt EVERY role: lint, format, typescript",
660
+ // Deliberately not enumerated here. A hand-written list drifts, and this one did: it
661
+ // still said "lint, format, typescript" after the build role shipped, so the help told
662
+ // adopters the build was not covered when it was. "Available now", below, is derived.
663
+ " sentinel --init --preset react # adopt every available role (see below)",
659
664
  " sentinel --init --typescript --preset react # set up the current module + workspace",
660
665
  " sentinel --run --typescript -- --noImplicitAny # ask the tool a question of your own"
661
666
  ].join("\n")