@geonosis/doctor 1.2.0 → 1.4.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 +69 -7
- package/dist/{chunk-ZJCUTDQW.js → chunk-R4OLFNI6.js} +805 -125
- package/dist/doctor-cli.js +81 -34
- package/dist/index.d.ts +41 -15
- package/dist/index.js +7 -1
- package/package.json +2 -2
package/dist/doctor-cli.js
CHANGED
|
@@ -3,58 +3,72 @@ import {
|
|
|
3
3
|
formatDoctor,
|
|
4
4
|
formatJson,
|
|
5
5
|
runDoctor
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-R4OLFNI6.js";
|
|
7
7
|
|
|
8
8
|
// src/doctor-cli.ts
|
|
9
9
|
import { resolve } from "path";
|
|
10
|
-
var
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
var ABOUT = {
|
|
11
|
+
baseline: `The ratchet's numbers at HEAD against another ref. A ratchet lowers its own baseline
|
|
12
|
+
when a number shrinks, so nothing inside one checkout can see a branch raise one back
|
|
13
|
+
up. OFF unless asked for: it is the only check that runs git, and this tool is run
|
|
14
|
+
over repos other people are working in.`,
|
|
15
|
+
deployed: `What the pipeline REPORTED deploying, in .geonosis/deployed.json, against what the
|
|
16
|
+
tree declares in the wrangler configs geonosis.json names and release.secrets.
|
|
17
|
+
"versions upload" applies no triggers, so a cron edited in a config is silently
|
|
18
|
+
ignored in production for ever with a green pipeline; a secret can be put outside the
|
|
19
|
+
gate entirely. SKIPs with the sentence when the file is absent \u2014 its absence is not a
|
|
20
|
+
pass \u2014 and reads the file rather than importing @geonosis/release.`,
|
|
21
|
+
drift: `The gates that were set up and are no longer running: a CI job switched off by a
|
|
22
|
+
condition that can never be true, a test file under a workspace with no test script, a
|
|
23
|
+
script handing bun/node/tsx a file that is not on disk, a workspace bin nothing links,
|
|
24
|
+
an integration directory the registry never names, a geonosis bin a git hook calls
|
|
25
|
+
through pnpm/npx/bunx and therefore cannot start, a law over the ceiling its own
|
|
26
|
+
geonosis.json declared, nothing enabling the plugin in either scope, and a
|
|
27
|
+
geonosis.json block no manifest declares a package for (or the reverse).`,
|
|
28
|
+
envelope: `The arithmetic under every other line: for each .geonosis/envelopes/<tool>.json a gate
|
|
29
|
+
wrote, considered === read + refused + excused. Four denominator bugs landed in one
|
|
30
|
+
day and every one of them was GREEN \u2014 a migrations run that reported on three of four
|
|
31
|
+
files, a plan check that printed "PASS \u2014 0 plan(s)" over a directory of twenty-one, a
|
|
32
|
+
parity run over a tree the second config ignored. Each published a numerator and no
|
|
33
|
+
denominator. Reads the files and imports nothing of the tools that wrote them; no
|
|
34
|
+
envelopes at all is a SKIP with the sentence.`,
|
|
35
|
+
exercised: `Every rule a config enables, against the corpus the loaded plugin ships. A rule at
|
|
36
|
+
"error" that can never fire is indistinguishable from a clean tree.`,
|
|
37
|
+
loaded: `The plugin oxlint would LOAD from each config's directory, against the version that
|
|
16
38
|
config's workspace DECLARES. oxlint resolves a jsPlugins specifier from the CONFIG
|
|
17
39
|
FILE's directory, so a nested copy left behind by a per-workspace install runs while
|
|
18
40
|
every manifest and the lockfile say otherwise \u2014 one consumer measured a whole bug
|
|
19
41
|
report against 0.3.0 on a repo pinned to 0.4.0. Every copy is found by RESOLUTION,
|
|
20
|
-
never by find: on pnpm the store keeps every version ever installed
|
|
21
|
-
|
|
22
|
-
exercised Every rule a config enables, against the corpus the loaded plugin ships. A rule at
|
|
23
|
-
"error" that can never fire is indistinguishable from a clean tree.
|
|
24
|
-
|
|
25
|
-
baseline The ratchet's numbers at HEAD against another ref. A ratchet lowers its own baseline
|
|
26
|
-
when a number shrinks, so nothing inside one checkout can see a branch raise one back
|
|
27
|
-
up. OFF unless asked for: it is the only check that runs git, and this tool is run
|
|
28
|
-
over repos other people are working in.
|
|
29
|
-
|
|
30
|
-
runner Workspaces whose test script's exit code is the only verdict. A pool exited 0 over
|
|
31
|
-
suites it had just reported as failing, for weeks, in a consumer.
|
|
32
|
-
|
|
33
|
-
observability
|
|
34
|
-
The exporter named by the "observability" block in geonosis.json: is a sink
|
|
42
|
+
never by find: on pnpm the store keeps every version ever installed.`,
|
|
43
|
+
observability: `The exporter named by the "observability" block in geonosis.json: is a sink
|
|
35
44
|
configured, is its endpoint reachable (a HEAD with a short timeout), and did an event
|
|
36
45
|
arrive inside maxAgeSeconds \u2014 read from the lastEventFile the sink writes, never from
|
|
37
46
|
this tool importing the library it is checking. A deploy job reported success having
|
|
38
47
|
deployed nothing and a /health answered ok over a dead database on the same
|
|
39
|
-
afternoon; both left a green build and a silent project
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
afternoon; both left a green build and a silent project.`,
|
|
49
|
+
runner: `Workspaces whose test script's exit code is the only verdict. A pool exited 0 over
|
|
50
|
+
suites it had just reported as failing, for weeks, in a consumer. A script with no
|
|
51
|
+
test file under it is a SKIP \u2014 there is no result for an exit code to be wrong about.`
|
|
52
|
+
};
|
|
53
|
+
var USAGE = `geonosis-doctor [--root <dir>] [--only <check,\u2026>] [--json] [--strict] [--baseline-against [<ref>]] [--oxlint <path>]
|
|
45
54
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
${CHECKS.length} questions a version bump is not finished until something has asked. Most are ways
|
|
56
|
+
enforcement has reported green while measuring nothing; drift asks whether the gate is still there
|
|
57
|
+
at all, and the last two ask whether what was reported is what happened.
|
|
58
|
+
|
|
59
|
+
With no arguments it runs every one of them over the working directory. A tree holding no
|
|
60
|
+
package.json and no .oxlintrc.json is REFUSED with exit 2 \u2014 there is nothing there to examine, and a
|
|
61
|
+
page of SKIPs is not a pass.
|
|
62
|
+
|
|
63
|
+
${CHECKS.map((check) => ` ${check.padEnd(11)} ${ABOUT[check]}`).join("\n\n")}
|
|
52
64
|
|
|
53
65
|
exercised reads the corpus the loaded plugin ships, and \u2014 when geonosis.json names one under
|
|
54
66
|
doctor.corpus \u2014 the corpus THIS repo ships for its own options. Three rules cannot be answered any
|
|
55
67
|
other way: layer-walls fires on a repo's own layer names, no-brand-names on its brand, and
|
|
56
68
|
plugin-route-namespaced on its package root, while the shipped corpus says acme and layers/core.
|
|
57
69
|
|
|
70
|
+
--print-config-shape every file this reads, and the keys it reads out of each
|
|
71
|
+
|
|
58
72
|
Exits 1 when any line is a FAIL or an UNJUDGED \u2014 a question this could not ask is not a pass \u2014 and
|
|
59
73
|
2 when the run could not be made at all. --strict promotes every WARN to a FAIL. --json prints the
|
|
60
74
|
whole report for a CI step to read.`;
|
|
@@ -100,10 +114,43 @@ var parseDoctorArgs = (argv, cwd) => {
|
|
|
100
114
|
strict
|
|
101
115
|
};
|
|
102
116
|
};
|
|
117
|
+
var CONFIG_SHAPE = `geonosis-doctor reads geonosis.json, geonosis.ratchet.json, .oxlintrc.json,
|
|
118
|
+
pnpm-workspace.yaml and .claude/settings.json
|
|
119
|
+
|
|
120
|
+
geonosis.json \u2192 "law"
|
|
121
|
+
file string? the law file to measure (default "CLAUDE.md")
|
|
122
|
+
maxLines number? the ceiling. Undeclared means UNJUDGED, never a default it fires on
|
|
123
|
+
geonosis.json \u2192 "observability"
|
|
124
|
+
sink string where this repo sends its errors
|
|
125
|
+
endpoint string the URL that must be reachable
|
|
126
|
+
lastEventFile string the file the sink writes on arrival
|
|
127
|
+
probe string? a command that answers instead of lastEventFile
|
|
128
|
+
maxAgeSeconds number how old the last event may be
|
|
129
|
+
geonosis.json \u2192 "release"
|
|
130
|
+
wrangler string[] the wrangler configs a deployment carries
|
|
131
|
+
wranglerEnv string? the named environment block to read
|
|
132
|
+
secrets string[] the secret names it carries
|
|
133
|
+
.oxlintrc.json
|
|
134
|
+
jsPlugins string[] the plugin specifiers oxlint would load
|
|
135
|
+
rules object the base rules, and the options each was given
|
|
136
|
+
overrides object[] files + rules; an entry REPLACES a rule's options for the files it
|
|
137
|
+
claims, last match winning \u2014 the same resolution oxlint does
|
|
138
|
+
geonosis.ratchet.json
|
|
139
|
+
the ratchet's own \u2014 run \`geonosis-ratchet --print-config-shape\`
|
|
140
|
+
pnpm-workspace.yaml
|
|
141
|
+
publicHoistPattern string[] the packages this repo claims are linked at the root, read as
|
|
142
|
+
text; a "*" is the only wildcard and it spans "/"
|
|
143
|
+
.claude/settings.json
|
|
144
|
+
enabledPlugins object what installs the kit's plugin in THIS repo`;
|
|
103
145
|
var main = async () => {
|
|
104
146
|
const argv = process.argv.slice(2);
|
|
105
147
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
106
148
|
process.stdout.write(`${USAGE}
|
|
149
|
+
`);
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
if (argv.includes("--print-config-shape")) {
|
|
153
|
+
process.stdout.write(`${CONFIG_SHAPE}
|
|
107
154
|
`);
|
|
108
155
|
return 0;
|
|
109
156
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
type Overrides = {
|
|
2
|
+
files: readonly string[];
|
|
3
|
+
rules: Record<string, unknown>;
|
|
4
|
+
}[];
|
|
5
|
+
|
|
1
6
|
/**
|
|
2
7
|
* The questions a bump is not finished until something has asked, in the order a run asks them.
|
|
3
|
-
* The first four are ways enforcement has reported green while measuring nothing; `
|
|
4
|
-
*
|
|
5
|
-
*
|
|
8
|
+
* The first four are ways enforcement has reported green while measuring nothing; `envelope` asks
|
|
9
|
+
* the arithmetic underneath all of them — whether a gate read as many things as it was handed;
|
|
10
|
+
* `drift` asks whether the gate is still there at all; `observability` and `deployed` ask the same
|
|
11
|
+
* question one layer out — whether what was reported is what happened.
|
|
6
12
|
*/
|
|
7
|
-
declare const CHECKS: readonly ["loaded", "exercised", "baseline", "runner", "drift", "observability", "deployed"];
|
|
13
|
+
declare const CHECKS: readonly ["loaded", "exercised", "baseline", "runner", "envelope", "drift", "observability", "deployed"];
|
|
8
14
|
type CheckName = (typeof CHECKS)[number];
|
|
9
15
|
/**
|
|
10
16
|
* `SKIP` is a first-class answer and is printed like any other: a check whose line is missing reads
|
|
@@ -29,6 +35,7 @@ declare class DoctorError extends Error {
|
|
|
29
35
|
constructor(message: string);
|
|
30
36
|
}
|
|
31
37
|
type Manifest = {
|
|
38
|
+
bin?: Record<string, string> | string;
|
|
32
39
|
dependencies?: Record<string, string>;
|
|
33
40
|
devDependencies?: Record<string, string>;
|
|
34
41
|
name?: string;
|
|
@@ -47,6 +54,8 @@ type DiscoveredConfig = {
|
|
|
47
54
|
/** Why this config could not be read. A config nobody can parse is a finding, never a skip. */
|
|
48
55
|
error?: string;
|
|
49
56
|
jsPlugins: string[];
|
|
57
|
+
/** Layers that REPLACE a rule's options for the files they claim — never merged into the base. */
|
|
58
|
+
overrides: Overrides;
|
|
50
59
|
path: string;
|
|
51
60
|
relative: string;
|
|
52
61
|
rules: Record<string, unknown>;
|
|
@@ -138,7 +147,7 @@ declare const READERS: Record<string, string>;
|
|
|
138
147
|
* block nothing reads. The other four checks ask whether a gate measures what it names; this one
|
|
139
148
|
* asks whether it is still there at all.
|
|
140
149
|
*/
|
|
141
|
-
declare const checkDrift: ({ readers, root, workspaces, }: {
|
|
150
|
+
declare const checkDrift: ({ readers, root, userSettings, workspaces, }: {
|
|
142
151
|
/**
|
|
143
152
|
* Which package reads which block. It is a parameter so a test can name one that can NEVER be
|
|
144
153
|
* installed: a fixture that turns on whether some real package happens to be present on the base
|
|
@@ -147,9 +156,35 @@ declare const checkDrift: ({ readers, root, workspaces, }: {
|
|
|
147
156
|
*/
|
|
148
157
|
readers?: Record<string, string>;
|
|
149
158
|
root: string;
|
|
159
|
+
/**
|
|
160
|
+
* The machine-wide settings, a parameter so a test never asks about the home directory it happens
|
|
161
|
+
* to run in — the same reason `readers` is one.
|
|
162
|
+
*/
|
|
163
|
+
userSettings?: string;
|
|
150
164
|
workspaces: Workspace[];
|
|
151
165
|
}) => Finding[];
|
|
152
166
|
|
|
167
|
+
/**
|
|
168
|
+
* The one line that catches a denominator bug: for every envelope a tool wrote,
|
|
169
|
+
* `considered === read + refused + excused`.
|
|
170
|
+
*
|
|
171
|
+
* Four of them landed in one day, all green — a migrations run that reported on three of four
|
|
172
|
+
* files, a plan check that printed `PASS — 0 plan(s)` over a directory of twenty-one, a parity run
|
|
173
|
+
* over a tree the second config had ignored, a validator that walked a list it had already
|
|
174
|
+
* filtered. Every one published a numerator and no denominator, so nothing could be wrong.
|
|
175
|
+
*
|
|
176
|
+
* This READS the files and imports nothing of the tools that wrote them — the same discipline
|
|
177
|
+
* `deployed` and `observability` follow. A check that needed the package it checks cannot run in
|
|
178
|
+
* the tree where that package is missing, which is the first case it exists to find; and this one
|
|
179
|
+
* has to work over a consumer's `.geonosis/` with no kit installed at all. The arithmetic is
|
|
180
|
+
* duplicated here on purpose: it is one comparison over three numbers, and it is the check.
|
|
181
|
+
*/
|
|
182
|
+
declare const ENVELOPES_DIR = ".geonosis/envelopes";
|
|
183
|
+
declare const NO_ENVELOPES = "no .geonosis/envelopes/*.json \u2014 the tools write one per run, so an absent envelope is a run nobody has made here yet, and it is not a balanced one";
|
|
184
|
+
declare const checkEnvelopes: ({ root }: {
|
|
185
|
+
root: string;
|
|
186
|
+
}) => Finding[];
|
|
187
|
+
|
|
153
188
|
/**
|
|
154
189
|
* The rules of one plugin a config actually turns on. A rule NAMED in a config is not a rule
|
|
155
190
|
* enabled by it — `"off"` is how a config records a rule it decided against, and counting those as
|
|
@@ -244,15 +279,6 @@ declare const repoCorpusOf: (root: string) => string | undefined;
|
|
|
244
279
|
declare const formatDoctor: ({ counts, findings, ok, root }: DoctorReport) => string;
|
|
245
280
|
declare const formatJson: (report: DoctorReport) => string;
|
|
246
281
|
|
|
247
|
-
/**
|
|
248
|
-
* What oxlint would load, asked the only way that answers on every package manager.
|
|
249
|
-
*
|
|
250
|
-
* oxlint resolves a `jsPlugins` specifier from the CONFIG FILE's directory, not the working
|
|
251
|
-
* directory, so the question is asked from a directory and never from the process's cwd. And it is
|
|
252
|
-
* asked of the RESOLVER: counting copies with `find` is a bun/npm check only — on pnpm the entries
|
|
253
|
-
* under `node_modules/@scope/` are symlinks into `.pnpm/`, which keeps every version ever
|
|
254
|
-
* installed, so the same count answers 7 on a correct tree and 0 with the store excluded.
|
|
255
|
-
*/
|
|
256
282
|
declare const resolveFrom: (dir: string, specifier: string) => string;
|
|
257
283
|
/** The package a resolved entry point belongs to: up until a manifest claims the name. */
|
|
258
284
|
declare const packageDirOf: (entry: string, name: string) => string;
|
|
@@ -287,4 +313,4 @@ declare const checkRunner: ({ ratchet, workspaces, }: {
|
|
|
287
313
|
workspaces: Workspace[];
|
|
288
314
|
}) => Finding[];
|
|
289
315
|
|
|
290
|
-
export { CHECKS, CONFIG_FILE, type CheckName, DEPLOYED_FILE, type DiscoveredConfig, DoctorError, type DoctorOptions, type DoctorReport, type Finding, GEONOSIS_FILE, type LastEventRecord, MANIFEST_FILE, type Manifest, NOT_WRITTEN, type ObservabilityConfig, RATCHET_FILE, READERS, type RatchetConfig, SCOPE, type Verdict, type Workspace, checkBaseline, checkDeployed, checkDrift, checkExercised, checkLoaded, checkObservability, checkRunner, corpusOfPlugin, declaredFor, defaultRef, discoverConfigs, discoverWorkspaces, enabledRulesOf, formatDoctor, formatJson, packageDirOf, pluginVersionOf, readConfig, readRatchet, relativePath, relativeToRoot, repoCorpusOf, resolveFrom, runDoctor, satisfies };
|
|
316
|
+
export { CHECKS, CONFIG_FILE, type CheckName, DEPLOYED_FILE, type DiscoveredConfig, DoctorError, type DoctorOptions, type DoctorReport, ENVELOPES_DIR, type Finding, GEONOSIS_FILE, type LastEventRecord, MANIFEST_FILE, type Manifest, NOT_WRITTEN, NO_ENVELOPES, type ObservabilityConfig, RATCHET_FILE, READERS, type RatchetConfig, SCOPE, type Verdict, type Workspace, checkBaseline, checkDeployed, checkDrift, checkEnvelopes, checkExercised, checkLoaded, checkObservability, checkRunner, corpusOfPlugin, declaredFor, defaultRef, discoverConfigs, discoverWorkspaces, enabledRulesOf, formatDoctor, formatJson, packageDirOf, pluginVersionOf, readConfig, readRatchet, relativePath, relativeToRoot, repoCorpusOf, resolveFrom, runDoctor, satisfies };
|
package/dist/index.js
CHANGED
|
@@ -3,15 +3,18 @@ import {
|
|
|
3
3
|
CONFIG_FILE,
|
|
4
4
|
DEPLOYED_FILE,
|
|
5
5
|
DoctorError,
|
|
6
|
+
ENVELOPES_DIR,
|
|
6
7
|
GEONOSIS_FILE,
|
|
7
8
|
MANIFEST_FILE,
|
|
8
9
|
NOT_WRITTEN,
|
|
10
|
+
NO_ENVELOPES,
|
|
9
11
|
RATCHET_FILE,
|
|
10
12
|
READERS,
|
|
11
13
|
SCOPE,
|
|
12
14
|
checkBaseline,
|
|
13
15
|
checkDeployed,
|
|
14
16
|
checkDrift,
|
|
17
|
+
checkEnvelopes,
|
|
15
18
|
checkExercised,
|
|
16
19
|
checkLoaded,
|
|
17
20
|
checkObservability,
|
|
@@ -34,21 +37,24 @@ import {
|
|
|
34
37
|
resolveFrom,
|
|
35
38
|
runDoctor,
|
|
36
39
|
satisfies
|
|
37
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-R4OLFNI6.js";
|
|
38
41
|
export {
|
|
39
42
|
CHECKS,
|
|
40
43
|
CONFIG_FILE,
|
|
41
44
|
DEPLOYED_FILE,
|
|
42
45
|
DoctorError,
|
|
46
|
+
ENVELOPES_DIR,
|
|
43
47
|
GEONOSIS_FILE,
|
|
44
48
|
MANIFEST_FILE,
|
|
45
49
|
NOT_WRITTEN,
|
|
50
|
+
NO_ENVELOPES,
|
|
46
51
|
RATCHET_FILE,
|
|
47
52
|
READERS,
|
|
48
53
|
SCOPE,
|
|
49
54
|
checkBaseline,
|
|
50
55
|
checkDeployed,
|
|
51
56
|
checkDrift,
|
|
57
|
+
checkEnvelopes,
|
|
52
58
|
checkExercised,
|
|
53
59
|
checkLoaded,
|
|
54
60
|
checkObservability,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geonosis/doctor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"types": "./dist/index.d.ts",
|
|
5
5
|
"description": "The adoption doctor — declared ≠ loaded, enabled ≠ exercised, a baseline that grew, a runner whose exit code is the only verdict.",
|
|
6
6
|
"keywords": [
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"dist"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@geonosis/lint-parity": "1.
|
|
38
|
+
"@geonosis/lint-parity": "1.4.0"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"oxlint": ">=1.77"
|