@hublo/sentinel 1.2.0-alpha.8 → 1.2.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';
@@ -8,6 +8,7 @@ import {
8
8
  VERBS,
9
9
  WORKSPACE_ROOT_MARKER,
10
10
  availableTargets,
11
+ buildConfigFile,
11
12
  declaredPresetFor,
12
13
  describeFramework,
13
14
  dispatch,
@@ -21,7 +22,7 @@ import {
21
22
  registerAdapters,
22
23
  resolve,
23
24
  resolveBin
24
- } from "../chunk-A25QVPXF.js";
25
+ } from "../chunk-Z5I6SEKF.js";
25
26
 
26
27
  // bin/sentinel.ts
27
28
  import { program } from "commander";
@@ -113,6 +114,30 @@ function resolveContext(cwd2, opts2) {
113
114
  );
114
115
  }
115
116
 
117
+ // src/roles/build/declined.ts
118
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
119
+ import { join as join3 } from "path";
120
+ var DEPRECATED_NX_BUILDER = "@nx/webpack:webpack";
121
+ function buildsWithDeprecatedExecutor(cwd2) {
122
+ const projectJson = join3(cwd2, "project.json");
123
+ if (!existsSync2(projectJson)) return false;
124
+ try {
125
+ const project = JSON.parse(readFileSync2(projectJson, "utf8"));
126
+ return project.targets?.build?.executor === DEPRECATED_NX_BUILDER;
127
+ } catch {
128
+ return false;
129
+ }
130
+ }
131
+ function explainDecline(cwd2) {
132
+ if (buildConfigFile(cwd2) !== void 0) {
133
+ 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
+ if (buildsWithDeprecatedExecutor(cwd2)) {
136
+ return ` This module still builds through ${DEPRECATED_NX_BUILDER}, which Nx v24 removes. It has no Vite config yet, so there is nothing for --build to adopt: add one that imports @hublo/sentinel/build/nest, then run this again. See docs/build-adoption.md.`;
137
+ }
138
+ return ` This module has neither a Vite config nor an Nx build target, so it builds nothing and --build is out of scope for it. Nothing was written, and nothing is wrong.`;
139
+ }
140
+
116
141
  // src/cli/run-init.ts
117
142
  function asMessage(error) {
118
143
  return error instanceof Error ? error.message : String(error);
@@ -151,9 +176,10 @@ async function runInit(ctx) {
151
176
  } catch (error) {
152
177
  if (error instanceof PresetUnsupportedError) {
153
178
  if (ctx.targetsExplicit) {
179
+ const hint = type === "build" ? explainDecline(module.root) : ` Pass --preset if it was detected wrongly (hoisted dependencies make detection fall back to "node").`;
154
180
  process.stderr.write(
155
181
  `
156
- sentinel (${type}): this module's preset is "${error.preset}", and --${type} has no adapter for it. Pass --preset if it was detected wrongly (hoisted dependencies make detection fall back to "node").
182
+ sentinel (${type}): this module's preset is "${error.preset}", and --${type} has no adapter for it.${hint}
157
183
  `
158
184
  );
159
185
  worst = Math.max(worst, 1);