@hublo/sentinel 1.2.0-alpha.1 → 1.2.0-alpha.11
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 +2 -2
- package/dist/bin/sentinel.d.ts +5 -0
- package/dist/bin/sentinel.js +57 -8
- package/dist/{chunk-FLJ2QNFF.js → chunk-6VOQDDZD.js} +649 -339
- package/dist/index.js +1 -2
- package/dist/roles/build/nest/toolchain.d.ts +90 -0
- package/dist/roles/build/nest/toolchain.js +254 -0
- package/dist/roles/build/toolchain.d.ts +5 -0
- package/dist/roles/build/toolchain.js +16 -0
- package/package.json +21 -3
- package/dist/chunk-XVDOQ3G3.js +0 -39
- package/dist/roles/build/react-app.d.ts +0 -112
- package/dist/roles/build/react-app.js +0 -126
package/README.md
CHANGED
|
@@ -151,7 +151,7 @@ pnpm dlx @hublo/sentinel@<exact-version> --inspect --typescript --module <name>
|
|
|
151
151
|
- [`docs/using-sentinel.md`](docs/using-sentinel.md) — every verb for every role, scoping a run to some files, what a fully adopted module looks like, and how versions move between modules.
|
|
152
152
|
- [`docs/lint-adoption.md`](docs/lint-adoption.md) — migrating a module from ESLint to Oxlint: the two steps, what `--init` writes and removes, the two react tiers, and the failures worth recognising.
|
|
153
153
|
- [`docs/format-adoption.md`](docs/format-adoption.md) — migrating a module from Prettier to oxfmt: why this config is materialized rather than a stub, how a module keeps its own formatting, and what did not survive the move.
|
|
154
|
-
- [`docs/build-adoption.md`](docs/build-adoption.md) — moving a React app's Vite toolchain into sentinel:
|
|
154
|
+
- [`docs/build-adoption.md`](docs/build-adoption.md) — moving a React app's Vite toolchain into sentinel: adoption changes the config's IMPORTS and nothing else, what sentinel owns versus what stays the app's, and why reading nothing is what makes losing nothing a guarantee.
|
|
155
155
|
- [`docs/typescript-adoption.md`](docs/typescript-adoption.md) — the adoption cheat sheet: the two adoption steps, the command model (verb x type x location), options, reading a report, and troubleshooting.
|
|
156
156
|
- [`docs/typescript-traces.md`](docs/typescript-traces.md) — a **generated, versioned** reference of live command + output traces (every verb, option, config result and edge case) against the mock monorepo. Regenerate after CLI changes with `pnpm docs:traces`.
|
|
157
157
|
|
|
@@ -161,7 +161,7 @@ Every check is described by three layers:
|
|
|
161
161
|
|
|
162
162
|
| Layer | Flag | What it is | Examples |
|
|
163
163
|
| -------------------- | --------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
164
|
-
| **target** (role) | `--lint`, `--typescript`, … | the _kind_ of check, stable | `lint` `format` `typescript` `build` `test` `static-analysis` `runtime-analysis`
|
|
164
|
+
| **target** (role) | `--lint`, `--typescript`, … | the _kind_ of check, stable | `lint` `format` `typescript` `build` `dev` `test` `static-analysis` `runtime-analysis` |
|
|
165
165
|
| **runner** (adapter) | `--runner=<tool>` | the _tool_ behind the target, swappable | lint: `eslint`/`biome`/`oxlint` · types: `tsc`/`tsgo` · build: `vite` · test: `vitest` |
|
|
166
166
|
| **preset** (preset) | detected / `--preset` | the _variant_ per stack (strict by default) | `react` `nest` `node` `svelte` (svelte: lint + format; no tsconfig preset yet, so the TypeScript role stands aside on those modules and the other two adopt) |
|
|
167
167
|
|
package/dist/bin/sentinel.d.ts
CHANGED
package/dist/bin/sentinel.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
LONG_RUNNING_TARGETS,
|
|
3
4
|
PRESET_NAMES,
|
|
4
5
|
PresetUnsupportedError,
|
|
5
6
|
SWEEPABLE_TARGETS,
|
|
@@ -7,28 +8,28 @@ import {
|
|
|
7
8
|
VERBS,
|
|
8
9
|
WORKSPACE_ROOT_MARKER,
|
|
9
10
|
availableTargets,
|
|
11
|
+
buildConfigFile,
|
|
10
12
|
declaredPresetFor,
|
|
11
13
|
describeFramework,
|
|
12
14
|
dispatch,
|
|
13
15
|
ensureWorkspacePrep,
|
|
14
16
|
findWorkspaceRoot,
|
|
15
17
|
inspectWorkspacePrep,
|
|
18
|
+
moduleName,
|
|
16
19
|
palette,
|
|
17
|
-
readNxProjectName,
|
|
18
20
|
readOwnVersion,
|
|
19
21
|
readProjectPackageJson,
|
|
20
22
|
registerAdapters,
|
|
21
23
|
resolve,
|
|
22
24
|
resolveBin
|
|
23
|
-
} from "../chunk-
|
|
24
|
-
import "../chunk-XVDOQ3G3.js";
|
|
25
|
+
} from "../chunk-6VOQDDZD.js";
|
|
25
26
|
|
|
26
27
|
// bin/sentinel.ts
|
|
27
28
|
import { program } from "commander";
|
|
28
29
|
|
|
29
30
|
// src/core/context.ts
|
|
30
31
|
import { existsSync } from "fs";
|
|
31
|
-
import {
|
|
32
|
+
import { join as join2 } from "path";
|
|
32
33
|
|
|
33
34
|
// src/core/discover-modules.ts
|
|
34
35
|
import { execFileSync } from "child_process";
|
|
@@ -96,7 +97,7 @@ function resolveContext(cwd2, opts2) {
|
|
|
96
97
|
if (opts2.ci) {
|
|
97
98
|
throw new Error("--ci selects the affected set from the workspace root; run it there.");
|
|
98
99
|
}
|
|
99
|
-
const name =
|
|
100
|
+
const name = moduleName(cwd2);
|
|
100
101
|
return { modules: [{ name, root: cwd2 }], scope: "cwd-module" };
|
|
101
102
|
}
|
|
102
103
|
if (atRoot) {
|
|
@@ -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
|
|
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);
|
|
@@ -463,6 +489,15 @@ async function runVerb(ctx) {
|
|
|
463
489
|
const { modules, scope } = resolveContext(ctx.cwd, { module: ctx.module, ci: ctx.ci });
|
|
464
490
|
const out = palette(process.stdout);
|
|
465
491
|
const err = palette(process.stderr);
|
|
492
|
+
const longRunning = ctx.targets.filter((target) => LONG_RUNNING_TARGETS.includes(target));
|
|
493
|
+
if (longRunning.length > 0 && modules.length > 1) {
|
|
494
|
+
process.stderr.write(
|
|
495
|
+
err.fail(
|
|
496
|
+
`sentinel: ${longRunning.map((t) => `--${t}`).join(", ")} starts a server that does not return, so it runs against ONE module. This resolved to ${modules.length} [${scope}]. Run it from inside the module's directory, or pass --module <name>.`
|
|
497
|
+
) + "\n"
|
|
498
|
+
);
|
|
499
|
+
return 1;
|
|
500
|
+
}
|
|
466
501
|
const shaped = ctx.verb === "run" && ctx.json ? "report" : ctx.verb;
|
|
467
502
|
const replacement = {
|
|
468
503
|
report: "--run --json",
|
|
@@ -579,6 +614,17 @@ registerAdapters();
|
|
|
579
614
|
var separator = process.argv.indexOf("--");
|
|
580
615
|
var toolArgs = separator === -1 ? [] : process.argv.slice(separator + 1);
|
|
581
616
|
var cliArgv = separator === -1 ? process.argv : process.argv.slice(0, separator);
|
|
617
|
+
var TARGET_HELP = {
|
|
618
|
+
lint: "linting",
|
|
619
|
+
format: "formatting",
|
|
620
|
+
typescript: "type checking",
|
|
621
|
+
build: "build",
|
|
622
|
+
dev: "dev server (long-running: never swept by an unqualified --run)",
|
|
623
|
+
test: "tests",
|
|
624
|
+
"static-analysis": "cycles, complexity, duplication, centrality",
|
|
625
|
+
"runtime-analysis": "bundle, Lighthouse, web vitals",
|
|
626
|
+
arch: "architecture boundaries"
|
|
627
|
+
};
|
|
582
628
|
program.name("sentinel").description("One CLI that guards code health: presets, analysis, and arch checks.").version(readOwnVersion()).configureHelp({ sortOptions: false }).showSuggestionAfterError(true).showHelpAfterError('(run "sentinel --help" for usage)').addHelpText(
|
|
583
629
|
"before",
|
|
584
630
|
[
|
|
@@ -589,7 +635,7 @@ program.name("sentinel").description("One CLI that guards code health: presets,
|
|
|
589
635
|
" --ci (affected), or all modules. --init targets one module only.",
|
|
590
636
|
""
|
|
591
637
|
].join("\n")
|
|
592
|
-
).option("--run", "execute the target tool").option("--inspect", "show the resolved configuration").option("--init", "set up a module: write its config stubs + the workspace prep it needs").option("--migrate", "planned: change an already-initialized setup (not available yet)").option("--report", "deprecated: use --run --json").option("--status", "deprecated: use --inspect").option(
|
|
638
|
+
).option("--run", "execute the target tool").option("--inspect", "show the resolved configuration").option("--init", "set up a module: write its config stubs + the workspace prep it needs").option("--migrate", "planned: change an already-initialized setup (not available yet)").option("--report", "deprecated: use --run --json").option("--status", "deprecated: use --inspect").option(
|
|
593
639
|
"--module <name>",
|
|
594
640
|
"from the workspace root: scope to one module (omit = all; inside a module dir, drop this)"
|
|
595
641
|
).option("--preset <name>", `the stack preset to apply (${PRESET_NAMES.join(", ")})`).option("--flavour <name>", "deprecated: use --preset").option("--runner <tool>", "override the default runner (e.g. eslint, biome)").option("--ci", "CI mode: from the root, only the affected modules; non-zero exit on failure").option("--fix", "auto-fix where applicable").option("--dry-run", "preview the changes without writing (--init)").option("--json", "machine-readable output, for every verb").option(
|
|
@@ -621,7 +667,10 @@ program.name("sentinel").description("One CLI that guards code health: presets,
|
|
|
621
667
|
`Available now: ${available.length ? available.map((t) => `--${t}`).join(", ") : "(none yet)"}`,
|
|
622
668
|
planned.length ? `Planned (ship in later tickets): ${planned.map((t) => `--${t}`).join(", ")}` : ""
|
|
623
669
|
].filter(Boolean).join("\n");
|
|
624
|
-
})
|
|
670
|
+
});
|
|
671
|
+
for (const target of TARGETS) program.option(`--${target}`, TARGET_HELP[target]);
|
|
672
|
+
program.option("--all", "every target");
|
|
673
|
+
program.parse(cliArgv);
|
|
625
674
|
var opts = program.opts();
|
|
626
675
|
function toCamel(flag) {
|
|
627
676
|
return flag.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|